關於InnoDB的索引大小

2021-09-23 23:23:27 字數 3077 閱讀 7307

背景

關於innodb內的索引大小。對於表

create table `testtb` (

`id` int(11) not null auto_increment,

`a` int(11) default null,

`b` int(11) default null,

`c` int(11) default null,

primary key (`id`),

key `i1` (`a`),

key `i2` (`a`,`id`),

key `i3` (`id`,`a`)

) engine=innodb default charset=utf8;

由於innodb在儲存索引的時候會自動取出重複的主鍵,原始碼分析見這裡

先說幾個結論

1)index i2 由於索引定義中已經包含pk  id,因此不會存兩份,實際就是(a, id)

2)index i1 本身要包含主鍵id,因此也是(a, id),與i2 相同

3)同理1,index i3 裡存的也只是(id, a)

異常

按照上面的結論,以下操作能發現「異常」

create table `t1` (

`id` int(11) not null auto_increment,

`a` int(11) default null,

`b` int(11) default null,

`c` int(11) default null,

primary key (`id`),

key `i2` (`a`,`id`)

) engine=innodb default charset=utf8;

create table `testtb` (

`id` int(11) not null auto_increment,

`a` int(11) default null,

`b` int(11) default null,

`c` int(11) default null,

primary key (`id`),

key `i3` (`id`,`a`)

) engine=innodb default charset=utf8;

接下來往這個兩個表中各插入5w行記錄,插入語句類似

foreach i in 1 to 5w

插入資料完成後,這個兩個表索引大小是否相同?

從show table status like 『%t1%』; 和show table status like 『%t2%』;的index_length可以看出來,是不同的,t1大一些。

儲存的行數相同,資料也相同,為什麼大小不一樣?

原因說明

主要在於插入順序導致的**。在上面的例子中,由於a,b,c的值都是隨機值,導致索引(a, id)是隨機的。id是遞增的,所以(id, a)是遞增的。

隨機插入索引和順序遞增插入索引之所以有差別,就在於隨機插入會導致更多的btree**。

這也就是為什麼在某些場景下,我們建議在表比較大的應用中,用自增id替代unique key (並非唯一的原因,也不是固定的規範,需要具體分析)。

驗證

有了上面的分析,要驗證就比較簡單了,把兩個表清空(truncate),

插入資料改為如下的語句

foreach i in 1 to 5w

這樣插入的每行都是(n,n,n,n), n為1到5w的遞增。這樣索引(a, id)也是順序遞增方式,與(id,a)一樣緊湊,再看show table status能發現一樣了。

有個工具

分兩個表驗證比較麻煩。這個是之前寫過的乙個分析檔案利用率的工具ibd_used

,可以看乙個表上各個索引的大小和索引上page的利用率。

用法./ibd_used testtb.ibd 0 n > k

說明:第乙個引數是要分析的ibd檔案 第

二、三個引數是起始、結束page_no。如果你要分析整個檔案,n可以輸入乙個很大的數就行。

結果中會輸出每個page的利用率,因此比較多,記得重定向輸出

最後幾行是整個索引的統計結果。

用文章開頭的例子和隨機值插入的case,得到的表中,執行

ibd_used data/test/testtb.ibd 0 99999999 > k

最後幾行如下

index_id:1517 rate 1751652/1949696=0.898423

index_id:1518 rate 701314/1212416=0.578443

index_id:1519 rate 701314/1212416=0.578443

index_id:1520 rate 700828/770048=0.910109

按順序對應索引,可以看出,i1和i2的利用率一模一樣,但跟i3 比起來就差多了。

grep -po " index_id:\d+" k | sort | uniq -c                                    

120 index_id:1517

75 index_id:1518

75 index_id:1519

48 index_id:1520

這個命令看每個索引占用多少page,與我們的結論一致:i3因為緊湊,所以占用更少的page。

innodb的索引機制

1 innodb將資料和索引儲存在一起 2 innodb索引是基於b tree的clustered index,b tree中的每個結點儲存key row data innodb中的第二個索引儲存,在搜尋時,先通過key找到pk,再通過pk搜尋b tree的結點,從中找到row data 3 由於聚...

InnoDB的索引模型

在 mysql 中,索引是在儲存引擎層實現的,儲存引擎沒有統一的索引標準,所以在不同儲存引擎中索引的工作方式並不一樣。即使多個儲存引擎支援同一種型別的索引,其底層的實現也可能不同。而在mysql 資料庫中,innodb 儲存引擎的使用最為廣泛,所以我們來了解一下innodb 的索引模型。innodb...

InnoDB索引實現

1 innodb的資料檔案本身就是索引檔案。從上文知道,myisam索引檔案 是分離的,索引檔案僅儲存資料記錄的位址。而在innodb中,表資料 檔案本身就是按b tree組織的乙個索引結構,這棵樹的葉節點data域 儲存了完整的資料記錄,這個索引的key是資料表的主鍵,因此innodb 表資料檔案...