前一段被問到一個平時沒有關注到有關於MYSQL索引相關的問題點,被問到一個表有3000萬記錄,假如有一列占8位字節的字段,根據這一列建索引的話索引樹的高度是多少?
這一問當時就被問蒙了,平時這也只關注MySQL索引一般都是都是用B+Tree來存儲維護索引的,還有一些復合索引的最左匹配原則等等,還真沒有實際關注過始即然用到索引能提升
查詢的效率,那么這個索引樹高是多少,給定表和索引字段后怎么計算出索引樹的高度?下面將用舉例的形式來說明如何計算索引樹的高度。
在舉例之前,先給出一個千萬級記錄表的索引的高度大概在3-5的樣,當時我看到這個數字時也是很驚訝的!
舉例前先做一下舉例時用到的公式的一些維度的說明
假設:
表的記錄數是N
每一個BTREE節點平均有B個索引KEY
那么B+TREE索引樹的高度就是logNB(等價於logN/logB)
由於索引樹每個節點的大小固定,所以索引KEY越小,B值就越大,那么每個BTREE節點上可以保存更多的索引KEY,也就是B值越大,索引樹的高度就越小,那么基於索引的查詢的性能就越高。所以相同表記錄數的情況下,索引KEY越小,索引樹的高度就越小。
現在我們假設表3000W條記錄(因為2^25=33554432),如果每個節點保存64個索引KEY,那么索引的高度就是(log2^25)/log64≈ 25/6 ≈ 4.17
通過上面的計算可知,要計一張表索引樹的高度,只需要知道一個節點有多,從而就能知道每個節點能存儲多少個索引KEY。現代數據庫經過不斷的探索和優化,並結合磁盤的預讀特點,每個索引節點一般都是操作系統頁的整數倍,操作系統頁可通過命令得到該值得大小,且一般是4094,即4k。而InnoDB的pageSize可以通過命令得到,默認值是16k。
以BIGINT為例,存儲大小為8個字節。INT存儲大小為4個字節(32位)。索引樹上每個節點除了存儲KEY,還需要存儲指針。所以每個節點保存的KEY的數量為pagesize/(keysize+pointsize)(如果是B-TREE索引結構,則是pagesize/(keysize+datasize+pointsize))。
假設平均指針大小是4個字節,那么索引樹的每個節點可以存儲16k/((8+4)*8)≈171。那么:一個擁有3000w數據,且主鍵是BIGINT類型的表的主鍵索引樹的高度就是(log2^25)/log171 ≈ 25/7.4 ≈ 3.38。
假設平均指針大小是8個字節,那么索引樹的每個節點可以存儲16k/((8+8)*8)≈128。那么:一個擁有3000w數據,且主鍵是BIGINT類型的表的主鍵索引樹的高度就是(log2^25)/log128 ≈ 25/7 ≈ 3.57
由上面的計算可知:一個千萬量級,且存儲引擎是MyISAM或者InnoDB的表,其索引樹的高度在3~5之間。