mysql 關於主鍵索引--節選丁奇部落格

zlingyi發表於2017-04-18
到底InnoDB會不會在索引末尾加上主鍵,什麼時候會加?

CREATE TABLE t ( a char(32) not null primary key, b char(32) not null, KEY idx1 (a,b), KEY idx2 (b,a) ) Engine=InnoDB;

插入部分資料後可以看到idx1和idx2兩個索引的大小相同。這說明idx1和idx2的內部結構是一樣的,因此 不可能 是idx1在內部存為(a,b,a)。

只要使用者定義的索引欄位中包含了主鍵中的欄位,那麼這個欄位就不會再被InnoDB自動加到索引中了,如果使用者的索引欄位中沒有完全包含主鍵欄位,InnoDB就會把剩下的主鍵欄位加到索引末尾。

因此我們最初的例子中, idx1 和 idx2 兩個索引內部大小完全一樣,沒有區別。

最後再補充下組合主鍵的例子:

CREATE TABLE t ( a char(32) not null, b char(32) not null, c char(32) not null, d char(32) not null, PRIMARY KEY (a,b) KEY idx1 (c,a), KEY idx2 (d,b) ) Engine=InnoDB;

這個表InnoDB會自動補全主鍵字典,idx1 實際上內部儲存為 (c,a,b),idx2 實際上內部儲存為 (d,b,a)。
但是這個自動新增的欄位,Server層是不知道的,所以MySQL最佳化器並不知道這個欄位的存在,所以如果你有一個查詢:

SELECT * FROM t WHERE d=x1 AND b=x2 ORDER BY a;

其實內部儲存的idx2(d,b,a)可以讓這個查詢完全走索引,但是由於Server層不知道,所以最終MySQL最佳化器可能選擇 idx2(d,b) 做過濾然後排序 a 欄位,或者直接用PK掃描避免排序。

而如果我們定義表結構的時候就定義為 KEY idx2(d,b,a) ,那麼MySQL就知道(d,b,a)三個欄位索引中都有,並且InnoDB發現使用者定義的索引中包含了所有的主鍵欄位,也不會再新增了,並沒有增加儲存空間。

因此,由衷的建議,所有的DBA建索引的時候,都在業務要求的索引欄位後面補上主鍵欄位,這沒有任何損失,但是可能給你帶來意外的驚喜。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28686045/viewspace-2137495/,如需轉載,請註明出處,否則將追究法律責任。

相關文章