1. 程式人生 > >資料庫原理,有深度好文

資料庫原理,有深度好文

轉自:http://blog.jobbole.com/100349/

一提到關係型資料庫,我禁不住想:有些東西被忽視了。關係型資料庫無處不在,而且種類繁多,從小巧實用的 SQLite 到強大的 Teradata 。但很少有文章講解資料庫是如何工作的。你可以自己谷歌/百度一下『關係型資料庫原理』,看看結果多麼的稀少【譯者注:百度為您找到相關結果約1,850,000個…】 ,而且找到的那些文章都很短。現在如果你查詢最近時髦的技術(大資料、NoSQL或JavaScript),你能找到更多深入探討它們如何工作的文章。

難道關係型資料庫已經太古老太無趣,除了大學教材、研究文獻和書籍以外,沒人願意講了嗎?

作為一個開發人員,我不喜歡用我不明白的東西。而且,資料庫已經使用了40年之久,一定有理由的。多年以來,我花了成百上千個小時來真正領會這些我每天都在用的、古怪的黑盒子。關係型資料庫非常有趣,因為它們是基於實用而且可複用的概念。如果你對了解一個數據庫感興趣,但是從未有時間或意願來刻苦鑽研這個內容廣泛的課題,你應該喜歡這篇文章。

雖然本文標題很明確,但我的目的並不是講如何使用資料庫。因此,你應該已經掌握怎麼寫一個簡單的 join query(聯接查詢)和CRUD操作(建立讀取更新刪除),否則你可能無法理解本文。這是唯一需要你瞭解的,其他的由我來講解。

我會從一些電腦科學方面的知識談起,比如時間複雜度。我知道有些人討厭這個概念,但是沒有它你就不能理解資料庫內部的巧妙之處。由於這是個很大的話題,我將集中探討

我認為必要的內容:資料庫處理SQL查詢的方式。我僅僅介紹資料庫背後的基本概念,以便在讀完本文後你會對底層到底發生了什麼有個很好的瞭解

【譯者注:關於時間複雜度。電腦科學中,演算法的時間複雜度是一個函式,它定量描述了該演算法的執行時間。如果不瞭解這個概念建議先看看維基百度百科,對於理解文章下面的內容很有幫助】

由於本文是個長篇技術文章,涉及到很多演算法和資料結構知識,你儘可以慢慢讀。有些概念比較難懂,你可以跳過,不影響理解整體內容。

這篇文章大約分為3個部分:

  • 底層和上層資料庫元件概況
  • 查詢優化過程概況
  • 事務和緩衝池管理概況

回到基礎

很久很久以前(在一個遙遠而又遙遠的星系……),開發者必須確切地知道他們的程式碼需要多少次運算。他們把演算法和資料結構牢記於心,因為他們的計算機執行緩慢,無法承受對CPU和記憶體的浪費。

在這一部分,我將提醒大家一些這類的概念,因為它們對理解資料庫至關重要。我還會介紹資料庫索引的概念。

O(1) vs O(n^2)

現今很多開發者不關心時間複雜度……他們是對的。

但是當你應對大量的資料(我說的可不只是成千上萬哈)或者你要爭取毫秒級操作,那麼理解這個概念就很關鍵了。而且你猜怎麼著,資料庫要同時處理這兩種情景!我不會佔用你太長時間,只要你能明白這一點就夠了。這個概念在下文會幫助我們理解什麼是基於成本的優化

概念

時間複雜度用來檢驗某個演算法處理一定量的資料要花多長時間。為了描述這個複雜度,電腦科學家使用數學上的『簡明解釋演算法中的大O符號』。這個表示法用一個函式來描述演算法處理給定的資料需要多少次運算。

比如,當我說『這個演算法是適用 O(某函式())』,我的意思是對於某些資料,這個演算法需要 某函式(資料量) 次運算來完成。

重要的不是資料量,而是當資料量增加時運算如何增加。時間複雜度不會給出確切的運算次數,但是給出的是一種理念。

圖中可以看到不同型別的複雜度的演變過程,我用了對數尺來建這個圖。具體點兒說,資料量以很快的速度從1條增長到10億條。我們可得到如下結論:

  • 綠:O(1)或者叫常數階複雜度,保持為常數(要不人家就不會叫常數階複雜度了)。
  • 紅:O(log(n))對數階複雜度,即使在十億級資料量時也很低。
  • 粉:最糟糕的複雜度是 O(n^2),平方階複雜度,運算數快速膨脹。
  • 黑和藍:另外兩種複雜度(的運算數也是)快速增長。

例子

資料量低時,O(1) 和 O(n^2)的區別可以忽略不計。比如,你有個演算法要處理2000條元素。

  • O(1) 演算法會消耗 1 次運算
  • O(log(n)) 演算法會消耗 7 次運算
  • O(n) 演算法會消耗 2000 次運算
  • O(n*log(n)) 演算法會消耗 14,000 次運算
  • O(n^2) 演算法會消耗 4,000,000 次運算

O(1) 和 O(n^2) 的區別似乎很大(4百萬),但你最多損失 2 毫秒,只是一眨眼的功夫。確實,當今處理器每秒可處理上億次的運算。這就是為什麼效能和優化在很多IT專案中不是問題。

我說過,面臨海量資料的時候,瞭解這個概念依然很重要。如果這一次演算法需要處理 1,000,000 條元素(這對資料庫來說也不算大)。

  • O(1) 演算法會消耗 1 次運算
  • O(log(n)) 演算法會消耗 14 次運算
  • O(n) 演算法會消耗 1,000,000 次運算
  • O(n*log(n)) 演算法會消耗 14,000,000 次運算
  • O(n^2) 演算法會消耗 1,000,000,000,000 次運算

我沒有具體算過,但我要說,用O(n^2) 演算法的話你有時間喝杯咖啡(甚至再續一杯!)。如果在資料量後面加個0,那你就可以去睡大覺了。

繼續深入

為了讓你能明白

  • 搜尋一個好的雜湊表會得到 O(1) 複雜度
    • 搜尋一個均衡的樹會得到 O(log(n)) 複雜度
    • 搜尋一個陣列會得到 O(n) 複雜度
    • 最好的排序演算法具有 O(n*log(n)) 複雜度
    • 糟糕的排序演算法具有 O(n^2) 複雜度

注:在接下來的部分,我們將會研究這些演算法和資料結構。

有多種型別的時間複雜度

  • 一般情況場景
  • 最佳情況場景
  • 最差情況場景

時間複雜度經常處於最差情況場景。

這裡我只探討時間複雜度,但複雜度還包括:

  • 演算法的記憶體消耗
  • 演算法的磁碟 I/O 消耗

當然還有比 n^2 更糟糕的複雜度,比如:

  • n^4:差勁!我將要提到的一些演算法具備這種複雜度。
  • 3^n:更差勁!本文中間部分研究的一些演算法中有一個具備這種複雜度(而且在很多資料庫中還真的使用了)。
  • 階乘 n:你永遠得不到結果,即便在少量資料的情況下。
  • n^n:如果你發展到這種複雜度了,那你應該問問自己IT是不是你的菜。

注:我並沒有給出『大O表示法』的真正定義,只是利用這個概念。可以看看維基百科上的這篇文章

合併排序

當你要對一個集合排序時你怎麼做?什麼?呼叫 sort() 函式……好吧,算你對了……但是對於資料庫,你需要理解這個 sort() 函式的工作原理。

優秀的排序演算法有好幾個,我側重於最重要的一種:合併排序。你現在可能還不瞭解資料排序有什麼用,但看完查詢優化部分後你就會知道了。再者,合併排序有助於我們以後理解資料庫常見的聯接操作,即合併聯接 。

合併

與很多有用的演算法類似,合併排序基於這樣一個技巧:將 2 個大小為 N/2 的已排序序列合併為一個 N 元素已排序序列僅需要 N 次操作。這個方法叫做合併

我們用個簡單的例子來看看這是什麼意思:

通過此圖你可以看到,在 2 個 4元素序列裡你只需要迭代一次,就能構建最終的8元素已排序序列,因為兩個4元素序列已經排好序了:

  • 1) 在兩個序列中,比較當前元素(當前=頭一次出現的第一個)
  • 2) 然後取出最小的元素放進8元素序列中
  • 3) 找到(兩個)序列的下一個元素,(比較後)取出最小的
  • 重複1、2、3步驟,直到其中一個序列中的最後一個元素
  • 然後取出另一個序列剩餘的元素放入8元素序列中。

這個方法之所以有效,是因為兩個4元素序列都已經排好序,你不需要再『回到』序列中查詢比較。

【譯者注:合併排序詳細原理,其中一個動圖(原圖較長,我做了刪減)清晰的演示了上述合併排序的過程,而原文的敘述似乎沒有這麼清晰,不動戳大。】

既然我們明白了這個技巧,下面就是我的合併排序虛擬碼。

C
12345678910111213arraymergeSort(arraya)if(length(a)==1)returna[0];endif//recursive calls[left_array right_array]:=split_into_2_equally_sized_arrays(a);arraynew_left_array:=mergeSort(left_array);arraynew_right_array:=mergeSort(right_array);//merging the 2 small ordered arrays into a big onearrayresult:=merge(new_left_array,new_right_array);returnresult;

合併排序是把問題拆分為小問題,通過解決小問題來解決最初的問題(注:這種演算法叫分治法,即『分而治之、各個擊破』)。如果你不懂,不用擔心,我第一次接觸時也不懂。如果能幫助你理解的話,我認為這個演算法是個兩步演算法:

  • 拆分階段,將序列分為更小的序列
  • 排序階段,把小的序列合在一起(使用合併演算法)來構成更大的序列

拆分階段

在拆分階段過程中,使用3個步驟將序列分為一元序列。步驟數量的值是 log(N) (因為 N=8, log(N)=3)。【譯者注:底數為2,下文有說明】

我怎麼知道這個的?

我是天才!一句話:數學。道理是每一步都把原序列的長度除以2,步驟數就是你能把原序列長度除以2的次數。這正好是對數的定義(在底數為2時)。

排序階段

在排序階段,你從一元序列開始。在每一個步驟中,你應用多次合併操作,成本一共是 N=8 次運算。

  • 第一步,4 次合併,每次成本是 2 次運算。
  • 第二步,2 次合併,每次成本是 4 次運算。
  • 第三步,1 次合併,成本是 8 次運算。

因為有 log(N) 個步驟,整體成本是 N*log(N) 次運算

相關推薦

資料庫原理深度

轉自:http://blog.jobbole.com/100349/ 一提到關係型資料庫,我禁不住想:有些東西被忽視了。關係型資料庫無處不在,而且種類繁多,從小巧實用的 SQLite 到強大的 Teradata 。但很少有文章講解資料庫是如何工作的。你可以自

Spark底層原理詳細解析(深度建議收藏)

### Spark簡介 Apache Spark是用於**大規模資料處理**的統一分析引擎,基於記憶體計算,提高了在大資料環境下資料處理的實時性,同時保證了**高容錯性**和**高可伸縮性**,允許使用者將Spark部署在大量硬體之上,形成叢集。 Spark原始碼從1.x的40w行發展到現在的超過100w行

泰勒公式淺談原理(轉) ----- 深度 一點是如何蘊含整個世界

泰勒公式淺談原理(轉)     上週寫完了《《三體》讀後思考-泰勒展開/維度打擊/黑暗森林》後收到一些郵件,進一步思考了關於泰勒展開的意義。也許我掌握的那些網路技術比如Linux Netfilter,NAT之類,太過底層太過小眾,所以大家幾乎都是沒有感興趣的

泰勒公式淺談原理(轉) ----- 深度 一點是如何蘊含整個世界

上週寫完了《《三體》讀後思考-泰勒展開/維度打擊/黑暗森林》後收到一些郵件,進一步思考了關於泰勒展開的意義。也許我掌握的那些網路技術比如Linux Netfilter,NAT之類,太過底層太過小眾,所以大家幾乎都是沒有感興趣的,倒是這種科普性質的文章和那些吐槽類的

tensorflow-梯度下降這一篇就夠了(深度)

前言最近機器學習越來越火了,前段時間斯丹福大學副教授吳恩達都親自錄製了關於Deep Learning Specialization的教程,在國內掀起了巨大的學習熱潮。本著不被時代拋棄的念頭,自己也開始研究有關機器學習的知識。都說機器學習的學習難度非常大,但不親自嘗試一下又怎麼

HBase 底層原理詳解(深度建議收藏)

## HBase簡介 HBase 是一個分散式的、面向列的開源資料庫。建立在 HDFS 之上。Hbase的名字的來源是 Hadoop database,即 Hadoop 資料庫。HBase 的計算和儲存能力取決於 Hadoop 叢集。 它介於 NoSql 和 RDBMS 之間,僅能通過主鍵(row ke

獵豹傅盛:升維思考降維攻擊!(深度

      轉載地址:http://www.woshipm.com/it/218149.html         前不久,我讀完《三體》,幾乎幫我建立了一個更高維度的世界觀和科學觀。因為你突然意識到,這個世界不

房價是一定要跌的(原創首發深度) ——何學林中國房地產大策劃之二

原創作者:何學林中國策劃一人 目前是房地產整個都在跌,但筆者是在房價一片喊漲聲中說的。當時遭到了普遍一致的反對,反對者的觀點是房價一定要漲,不可能跌,因為地球只有一個,土地越來越少,所以房價一定是 漲的。現在看來這種觀點和理由很幼稚,但當時確實都持這種觀點,在房

(深度)重構CMDB避免運維之恥

CMDB,幾乎是每個運維人都繞不過去的字眼,但又是很多運維人的痛,因為CMDB很少有成功的,因此我也把它稱之為運維人的恥辱。 那麼到底錯在哪兒了?該如何去重構它? 今天我想從我的角度來和大家探討一下業務失敗的原因,基於失敗再去看重構的邏輯,也許會成功。 從失敗中尋找成功的邏輯,往往是最有效的,那

高新技術企業認定史上最詳細的申請攻略!(深度

相關 str 直接 方式 項目 微信 組織 名片 數據 在市場廣闊的今天,基本每個省和市地×××府都會建立產業園區或高新技術企業優化孵化帶,提供各種政策支持、稅收優惠以及財政補助。同時,高新技術企業資質對企業來說是一張閃亮的名片,相當於中國的品牌馳名商標,不僅能夠為企業帶來

為什麼你看了很多書 卻依然沒有洞見 (深度

前幾天有人在知乎上問: 今天就回答下很多人問了很久的這個問題,並且解釋一下如何構建系統化的知識體系。 我想很多人看到這個問題,期待的答案是一個書單,可是我要告訴你這並沒有什麼卵用。 我想大部分人都經歷過高中,你會發現高考650分的人和450分的人

深度|TCP連線的狀態詳解以及故障排查技術人員必備技能

我們通過了解TCP各個狀態,可以排除和定位網路或系統故障時大有幫助。 1、TCP狀態 瞭解TCP之前,先了解幾個命令: li

Android Jetpack從入門到精通(深度值得收藏)

前言 即學即用Android Jetpack系列Blog的目的是通過學習Android Jetpack完成一個簡單的Demo,本文是即學即用Android Jetpack系列Blog的第一篇。 記得去年第一次參加谷歌開發者大會的時候,就被Navigation的圖形導航介面給迷住了,一句臥槽就代表了小王的全部心

Flink 中極其重要的 Time 與 Window 詳細解析(深度建議收藏)

### 前言 Flink 是流式的、實時的 計算引擎 上面一句話就有兩個概念,一個是流式,一個是實時。 **流式**:就是資料來源源不斷的流進來,也就是資料沒有邊界,但是我們計算的時候必須在一個有邊界的範圍內進行,所以這裡面就有一個問題,邊界怎麼確定? 無非就兩種方式,**根據時間段或者資料量進行確定

Spark效能調優-RDD運算元調優篇(深度面試常問建議收藏)

## RDD運算元調優 不廢話,直接進入正題! #### 1. RDD複用 在對RDD進行運算元時,要避免相同的運算元和計算邏輯之下對RDD進行重複的計算,如下圖所示: ![RDD的重複計算](https://cdn.jsdelivr.net/gh/sunmyuan/cdn/210228_1.png)

文化熏陶--深度

style htm tro color 為什麽 blank https 設計 -- 01、為什麽日本這個國家值得設計師去旅行? 02、朱學東:我需要用讀書讓自己不墮落! 文化熏陶--深度好文

思維的八層境界(深度

導讀 有道 一個 曾經 大學 運用 常常 提高 必要條件 導讀:今天,越來越多的人認識到,學習最重要的目標並不是掌握一些特定的知識,也不是那些可以很容易通過移動互聯網借助"百度"、"谷歌"等工具搜索到的特定知識,而是發展自己的思維! 在世界快速變化的時代,思維是最重要的核心

黑客滲透、網絡運維、微服務架構、電商平臺高可用??????更多請看本期推薦文章精選

黑客滲透 微服務 架構 因為最近手頭事情比較多,有好幾周沒有更新文章精選了。不知道大家有沒有想我啊。好了廢話不多說,開始更新精選文章: Redis漏洞利用與防禦 作者:simeon2005簡介:Redis在大公司被大量應用,通過筆者的研究發現,目前在互聯網上已經出現Redis未經授權病毒似自動

異步原創征集令一篇一本書!

Markdown 活動征集 點擊上方“異步社區”,選擇“置頂公眾號”技術幹貨,第一時間送達各位異步社區的小夥伴和大神,大家好!我是你們的異步君,就是一直被你們吐槽的,躲在異步客服後面的異步君。對,尤其最近新版上線後,被吐槽更激烈的異步君!之前大家一致吐槽異步君:想在異步社區寫個技術文章都難啊!社區編輯

時間序列預測——深度

原文地址:https://medium.com/open-machine-learning-course/open-machine-learning-course-topic-9-time-series-analysis-in-python-a270cb05e0b3 Open Machine Learnin