前言傳統關係型資料庫,也就是建立在關聯式模式基礎之上的資料庫。關係型資料庫本身基於關係代數的數學理論,關聯式模式是70年代埃德加·科德首次提出的,而該模型成為了關係型資料庫的基礎。目前市面上眾多的傳統關係型資料庫均是基於B族樹實現的,至於傳統關係型資料庫的眾多特性這裡就不進行論述了,在這裡只想分析一下基於B族樹的傳統關係型資料庫的IO瓶頸。
基於B族樹的資料庫IO瓶頸分析
磁碟屬於外儲存空間的一種,其特點是容量非常大,價格相對低廉,但是存取速度有限,尤其是隨機存取速度還是很慢的。磁碟IO操作中磁頭反覆移動會耗費很多時間,因此進行隨機的讀寫時,磁碟磁頭的轉動所花費的時間是相當可觀的,造成了隨機讀寫速度非常的慢。此外,磁碟讀寫是以資料區塊為基本單位,每次都要讀取資料時要把包含該資料的資料區塊讀出來。因此資料順序存放能夠加速磁碟的讀寫速度。總的來說,磁碟是容量大價格低廉的存放裝置,磁碟隨機讀寫會造成磁頭頻繁的移動,開銷很大,要盡量避免這種開銷。
傳統的關係型資料庫一般採用B族樹(B樹、B+樹等)作為儲存的基礎資料結構。B族樹是一種多路平衡搜尋樹,其作為資料庫的基礎資料結構的最大優點是效率很高,可以有效降低磁碟IO。下面再仔細分析一下B樹:
我們設有一顆階數為m(M應該大於等於2)的B樹,那麼該樹中的每個節點最多有m個孩子,除此之外還有如下特點:
若根節點有孩子(也即非葉子節點),則其至少有2個孩子;
所有的葉子節點都在同一層;
除了根節點,其他每個非葉子節點至少有upper(m/2)個子樹,upper為向上取整;
非葉子層存有指向下一層的指標,根據本層的資料和下一層的資料將指標指向合適的位置,指標指向下一層位置左邊的資料小於指標位置的資料,而指標指向下一層位置右邊的資料大於指標本層位置的資料,這樣就完成了一層一層的索引關係。
對一棵B樹進行尋找資料時,會從根節點開始,根據要找資料的key與當前的key進行比較,一層一層的向下尋找,直到找到該key或者到達葉子節點時仍未找到為止。每個節點都是儲存在磁碟中,那麼不難看出,一共最多需要樹的高度次磁碟IO(這裡忽略掉記憶體讀取與CPU的開銷,因為與磁碟IO相比這些開銷非常非常小)。那麼B樹的高度是多少呢? 是logm((n+1)/2)+1,推導請查閱演算法導論等書籍即可。這裡我們設B為(n+1)/2,那麼樹的高度為logm(B)+1,也就是說基於B樹的資料庫,進行一次key查詢(基於數值點的查詢)需要最多訪問logm(B)+1次磁碟,這個效率其實還是很高效的。
下面討論對一棵基於B族樹的資料庫進行插入操作。插入一個資料,需要從根節點開始進行比較,一層一層的向下找合適的位置,最終將值插入到B族樹中。若對一個建立的資料庫,對該資料庫進行大量資料插入操作,如果這些資料已經排好順序了,那麼每次的插入操作在磁碟的位置都會緊挨著上一次的操作位置,這樣這些操作寫到磁碟中都會是順序寫,因此效率比較高。但是若要插入的大量資料都是隨機且未排序的,那麼這些資料所在的塊在磁碟中就不會挨著,因此也就是會造成大量的隨機寫操作,其插入效率會非常的低下。插入資料的操作是資料庫中經常發生的操作,若隨機的插入大量資料,很難避免大量的磁碟隨機寫,磁頭頻繁的移動消耗掉大量的時間,因此對於隨機的大量資料插入操作,磁碟IO是很嚴重的效能瓶頸。
下面討論一下對一棵基於B族樹的資料庫進行範圍查詢。對於一棵新建立的B族樹,其葉子節點在磁碟上通常是順序存放的,對其進行範圍查詢時,會對磁碟進行大量的順序讀操作,由於是順序的讀,不需要頻繁的移動磁頭,因此其效率非常的高,速度非常的快。相比於新建立的B族樹,若是一棵經過大量插入、刪除、修改的B族樹就沒有這樣的範圍查詢效能了。一棵使用過(插入、刪除、修改等操作)很久的B族樹,進行範圍查詢時,由於葉子節點將會散布到磁碟的各個地方,因此會造成大量的隨機磁碟讀操作,造成磁頭的頻繁移動,消耗大量的時間,因此效率是十分低下的,磁碟將成為範圍查詢的瓶頸。
總的來說,對基於B族樹的資料庫進行插入操作與範圍尋找(使用很久的B族樹)時會有大量的隨機磁碟IO,因此其效能並不是很好。
解決方案
針對前面分析的瓶頸,我們在這裡嘗試去尋找解決這些問題的方法。磁碟IO瓶頸一直是資料庫需要面臨的問題,這裡所說的插入與範圍查詢只是特點比較鮮明、對效能損失比較大的操作。解決這一類問題我們有兩種思路:其一為加快磁碟的讀寫速度;其二為儘力避免隨機讀寫,將隨機讀寫轉化為部分隨機甚至小部分隨機,乃至全部順序讀寫。
針對第一種思路,我們可以使用效能更加好的磁碟,甚至使用SSD代替傳統磁碟。一種比較好的方法是使用SSD,在記憶體和磁碟之間再加一層緩衝,這樣可以兼顧效率和花費,性價比比較好。目前facebook出的flashcache就可以實現這一功能,將其應用在mysql上,能夠顯著的提升mysql的效能。
針對第二種思路,我們可以改換B族樹為其他的資料結構,例如要改善插入效能可以使用基於追加日誌的方式實現資料庫,所有插入資料都寫到日誌的尾端,因此插入操作變成了順序磁碟IO,效率會非常的高。此外使用分形樹等技術也可以。關於分形樹等較新的資料庫技術,以後有時間再寫專門介紹的文章。
小結
基於B族樹的一些傳統關係型資料庫在面對海量資料以及海量操作時會有嚴重的磁碟IO瓶頸,例如隨機插入資料,範圍尋找等操作的效率並不高,可以根據實際的需求來調整資料庫,開發出符合新需求的資料存放區產品。