目錄
一、什麼是索引
索引是存儲引擎用於快速找到記錄的一種數據結構,不同的索引類型底層採用不同的數據結構。索引優化應該是查詢性能優化中最有效的手段。索引可以輕易將查詢性能提高几個數量級,“最優”的索引有時比“好的”索引性能要好兩個數量級。索引的優點可以簡單歸納如下:
- 索引大大減少了服務器需要掃描的數據量。
- 索引可以幫助服務器避免排序、分組和臨時表。
- 索引可以將隨機I/O變爲順序I/O 。
只有當索引幫助存儲引擎快速查找到記錄帶來的好處大於其帶來的額外工作時,索引纔是有效的。對於非常小的表,大部分情況下簡單的全表掃描更高效;對於中到大型的表,索引纔會變得更高效。
二、innodb索引的類型
innodb是MySQL數據庫的默認存儲引擎,也是目前企業生產環境中使用最多的存儲引擎,所以這裏就直接總結innodb支持的索引類型。
1.聚簇索引
聚簇索引實際上在同一個結構中保存了B+Tree索引和數據行。當表有聚簇索引時,它的數據行實際上存放在索引的葉子頁(leaf page)中。因爲無法同時把數據行放在兩個不同的地方,所以一個表只能有一個聚簇索引。
聚簇索引默認是主鍵,如果表中沒有定義主鍵,InnoDB 會選擇一個唯一的非空索引代替。如果沒有這樣的索引,InnoDB 會隱式定義一個主鍵來作爲聚簇索引。InnoDB 只聚集在同一個頁面中的記錄。包含相鄰健值的頁面可能相距甚遠。如果你已經設置了主鍵爲聚簇索引,必須先刪除主鍵,然後添加我們想要的聚簇索引,最後恢復設置主鍵即可。
2.非聚簇索引(輔助索引、二級索引)
innodb中,在聚簇索引之上創建的索引稱之爲輔助索引,輔助索引訪問數據總是需要二次查找,非聚簇索引都是輔助索引,像複合索引、前綴索引、唯一索引,輔助索引葉子節點存儲的不再是行的物理位置,而是主鍵值。
三、B+Tree的特點
innodb底層採用B+Tree結構,這意味着所有的值都是按順序存儲的,並且每一個葉子頁到根的距離相同;因爲B+Tree按照順序存儲數據,所以MySQL可以用來做order by和group by。因爲索引中存儲了實際的列值,所有某些查詢只使用索引就能夠完成全部的查詢,即覆蓋索引。
- 聚簇索引插入的速度嚴重依賴於插入順序。
待補充。
四、面試題
1. 爲什麼MySQL的索引要使用B+樹而不是其它樹形結構?比如B樹?
簡單版本回答是:因爲B樹不管葉子節點還是非葉子節點,都會保存數據,這樣導致在非葉子節點中能保存的指針數量變少(有些資料也稱爲扇出),非葉子節點保存的指針少的情況下,又要保存大量數據,只能增加樹的高度,導致IO操作變多,查詢性能變低。
2. InnoDB一棵B+樹可以存放多少行數據?
問題的簡單回答是:約2千萬行。 InnoDB存儲引擎的最小存儲單元是頁,InnoDB頁的大小默認是16k,數據表中的數據都是存儲在頁中的,所以一個頁中能存儲多少行數據呢?假設一行數據的大小是1k,那麼一個頁可以存放16行這樣的數據。如果採用B+樹的方式組織這些數據。如圖所示:
頁可以用於存放數據也可以用於存放鍵值+指針,在B+樹中葉子節點存放數據,非葉子節點存放鍵值+指針。索引組織表通過非葉子節點的二分查找法以及指針確定數據在哪個頁中,進而在去數據頁中查找到需要的數據;
這裏我們先假設B+樹高爲2,即存在一個根節點和若干個葉子節點。那麼現在我們需要計算出非葉子節點能存放多少指針,其實這也很好算,我們假設主鍵ID爲bigint類型,長度爲8字節,而指針大小在InnoDB源碼中設置爲6字節,這樣一共14字節,我們一個頁中能存放多少這樣的單元,其實就代表有多少指針,即16384/14=1170。
上文我們已經說明單個葉子節點(頁)中的記錄數=16K/1K=16。(這裏假設一行記錄的數據大小爲1k,實際上現在很多互聯網業務數據記錄大小通常就是1K左右)。
那麼可以算出一棵高度爲2的B+樹,能存放1170*16=18720條這樣的數據記錄。
根據同樣的原理我們可以算出一個高度爲3的B+樹可以存放:1170117016=21902400條這樣的記錄。所以在InnoDB中B+樹高度一般爲1-3層,它就能滿足千萬級的數據存儲。在查找數據時一次頁的查找代表一次IO,所以通過主鍵索引查詢通常只需要1-3次IO操作即可查找到數據。
五、參考資料
- InnoDB一棵B+樹可以存放多少行數據?
- 《高性能MySQL》