Mysql的幾個靈魂拷問(二)

今天這篇主要是針對索引,開篇前先對Mysql數(shù)據(jù)庫的性能有個整體的認識,一般來講8c16g的數(shù)據(jù)庫qps在1000~2000,而16c32g的數(shù)據(jù)庫 qps在2000~4000左右,我們講qps也一般是針對單個系統(tǒng)、服務的性能衡量,而tps:一個業(yè)務系統(tǒng)(請求會調(diào)用多個其他服務)的性能衡量。

索引篇


索引為什么要放在磁盤中

上一篇數(shù)據(jù)更新流程中,有講Innodb引擎會在內(nèi)存引入buffer pool,但是由于內(nèi)存容易丟失,一般而言會配合各種日志和刷盤策略,將數(shù)據(jù)持久化在磁盤文件中,但是和內(nèi)存相比,從磁盤中讀取數(shù)據(jù)的速度會慢上百倍千倍甚至萬倍,所以,我們應當盡量減少從磁盤中讀取數(shù)據(jù)的次數(shù)。另外,從磁盤中讀取數(shù)據(jù)時,都是按照磁盤塊來讀取的,并不是一條一條的讀。如果我們能把盡量多的數(shù)據(jù)放進磁盤塊中,那一次磁盤讀取操作就會讀取更多數(shù)據(jù),那我們查找數(shù)據(jù)的時間也會大幅度降低。如果采用樹這種數(shù)據(jù)結(jié)構(gòu)作為索引的數(shù)據(jù)結(jié)構(gòu),那每查找一次數(shù)據(jù)就需要從磁盤中讀取一個節(jié)點,也就是我們說的一個磁盤塊。

為什么不用平衡二叉樹(B-Tree)作為索引呢?

平衡二叉樹每個節(jié)點只存儲一個鍵值和數(shù)據(jù)的,這就意味著每個磁盤塊僅僅存儲一個鍵值和數(shù)據(jù)!存的越多,二叉樹的節(jié)點也會越多,并且高度也會極其高,查找數(shù)據(jù)時也會進行很多次磁盤 IO,效率也非常低下!為了解決這個問題,就可以采用 B 樹結(jié)構(gòu)來解決層級過高。

B樹的每個節(jié)點稱為頁,頁就是前面提到的磁盤塊,B 樹相對于平衡二叉樹,每個節(jié)點存儲了更多的鍵值(key)和數(shù)據(jù)(data),并且每個節(jié)點擁有更多的子節(jié)點,子節(jié)點的個數(shù)一般稱為階。 基于這個特性,B 樹查找數(shù)據(jù)讀取磁盤的次數(shù)將會很少,數(shù)據(jù)的查找效率也會比平衡二叉樹高很多。

為什么要用B+樹?

  • B 樹節(jié)點中不僅存儲鍵值,也會存儲數(shù)據(jù),而B+ 樹非葉子節(jié)點上是不存儲數(shù)據(jù)的,僅存儲鍵值,如果不存儲數(shù)據(jù),那么就會存儲更多的鍵值,層高基本不會因為數(shù)據(jù)擴大而增高(三層樹結(jié)構(gòu)大概可以存放兩千萬數(shù)據(jù)量)。
  • B+樹有利于磁盤的IO,數(shù)據(jù)越多,只需要提升樹的階數(shù)(節(jié)點的子節(jié)點樹)即可,樹就會更矮更胖,IO次數(shù)就更少。
  • B+樹的所有數(shù)據(jù)都在葉子節(jié)點上,所以B+樹的查詢效率穩(wěn)定,一般都是查詢3次(根節(jié)點存放在內(nèi)存中)。B+ 樹索引的所有數(shù)據(jù)均存儲在葉子節(jié)點,而且數(shù)據(jù)是按照順序排列的。范圍查找,排序查找,分組查找以及去重查找變得異常簡單,而B 樹因為數(shù)據(jù)分散在各個節(jié)點,要實現(xiàn)這一點是很不容易的。
  • B+ 樹中各個頁之間是通過雙向鏈表連接的,葉子節(jié)點中的數(shù)據(jù)是通過單向鏈表連接的。在 InnoDB 中,我們通過數(shù)據(jù)頁之間通過雙向鏈表連接以及葉子節(jié)點中數(shù)據(jù)之間通過單向鏈表連接的方式可以找到表中所有的數(shù)據(jù)。

底層的索引結(jié)構(gòu)

MySQL的數(shù)據(jù)是以頁為基本單位組合而成的,頁的大小是16KB,里面包含我們的多條數(shù)據(jù),它還有指向下一頁的指針和指向上一頁的指針。Mysql取頁還有一個預讀機制(數(shù)據(jù)庫在查詢到一條數(shù)據(jù)的時候會把頁中相鄰的數(shù)據(jù)也取出來)。

將一個節(jié)點的大小設(shè)為等于一個頁,這樣每個節(jié)點只需要一次I/O就可以完全載入。假設(shè)B+Tree的高度為h,一次檢索最多需要h-1次I/O(根節(jié)點常駐內(nèi)存),復雜度O(h) = O(logmN)。實際應用場景中,M通常較大,常常超過100,因此樹的高度一般都比較小,通常不超過3。

Mysql底層的B+樹結(jié)構(gòu)

Mysql會采用頁目錄的目錄項來指向一行數(shù)據(jù),這條數(shù)據(jù)就是存在于這個目錄項中的最小數(shù)據(jù),那么就可以通過頁目錄來查找所需數(shù)據(jù)。非葉子節(jié)點是雙向鏈表,葉子節(jié)點是單向鏈表。

B+樹的單雙鏈表

每個節(jié)點就可以理解為是一個頁,而葉子節(jié)點也就是數(shù)據(jù)頁,除了葉子節(jié)點以外的節(jié)點就是目錄頁。非葉子節(jié)點只存放了索引,而只有葉子節(jié)點中存放了真實的數(shù)據(jù)。

B+
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容