索引面試題分析


 

Mysql 系列文章主頁 

 

===============

 

1 准備數據

1.1 建表

DROP TABLE IF EXISTS test03;
CREATE TABLE test03 (
    id INT PRIMARY KEY auto_increment,
    c1 char(10),
    c2 char(10),
    c3 char(10),
    c4 char(10),
    c5 char(10)
);

1.2 插入數據

INSERT INTO test03(c1, c2, c3, c4, c5) VALUES('a1', 'a2', 'a3', 'a4', 'a5');
INSERT INTO test03(c1, c2, c3, c4, c5) VALUES('b1', 'b2', 'b3', 'b4', 'b5');
INSERT INTO test03(c1, c2, c3, c4, c5) VALUES('c1', 'c2', 'c3', 'c4', 'c5');
INSERT INTO test03(c1, c2, c3, c4, c5) VALUES('d1', 'd2', 'd3', 'd4', 'd5');

2 測試&Explain分析

2.1 建立索引

CREATE INDEX idx_c1234 ON test03(c1, c2, c3, c4);

2.2 測試

Case#1:用到一個索引(注意:key_len=31)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1';

Case#2:用到兩個索引(注意:key_len=62)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2';

Case#3:用到三個索引(注意:key_len=93)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2' AND c3 = 'a3';

Case#4:用到四個索引(注意:key_len=124)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2' AND c3 = 'a3' AND c4 = 'a4';

Case#5:用到四個索引(注意:這里的查詢條件順序是 1 2 4 3 而不是 1 2 3 4)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2' AND c4 = 'a4' AND c3 = 'a3';

Case#6:用到四個索引(這里的順序是 4 3 2 1)

EXPLAIN SELECT * FROM test03 WHERE c4 = 'a4' AND c3 = 'a3' AND c2 = 'a2' AND c1 = 'a1';

Case#7:用到了三個索引(注意:第三個查詢條件是大於)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2' AND c3 > 'a3' AND c4 = 'a4';

結果:

  • key_len=93
  • type=range
  • ref=Null
  • 由以上三點可推知:使用了三個索引(使用到了 1 2 3 三個索引;由於范圍之后全失效,所以第四個索引沒有被使用到)

Case#8:用到了四個索引

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2' AND c4 > 'a4' AND c3 = 'a3';

結果:

  • key_len=124
  • type=range
  • ref=Null
  • 使用到了四個索引

分析:Mysql很聰明,查詢優化器會分析,得出 1 2 3 是常量,4 是范圍查詢的結論,於是,四個索引都能被使用,且 type=range。

Case#9:用到了 1 2 兩個索引

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2' ORDER BY c3;

說明:索引有兩個功能(查找和排序),所以這里的 c3 實際上還是使用上了索引的,只是它的用處是在排序(而不是查找;對比 Case#11 的結果更容易理解)。

Case#10:用到了 1 2 兩個索引

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2' AND c4 = 'a4' ORDER BY c3;

Case#11:用到了 1 2 兩個索引

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2' ORDER BY c4;

結果:key_len=62 說明確實用到了兩個索引,但是,由於建立的索引是 1 2 3 4 而此Sql是查詢 1 2 然后按照 4 來排序(中間斷掉了 3),於是出現了 Using filesort!對比 Case#9 的結果,它的Sql是查詢 1 2 然后按照 3 來排序,所以沒有出現 Using filesort。

Case#12:用到了一個索引

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c5 = 'a5' ORDER BY c2, c3;

說明:這里只用到了 c1 一個索引,同時 c2 c3 用於排序,沒有出現 Using filesort(可以和 Case#11 進行對比)。

Case#13:用到了一個索引(注意:ORDER BY 后面是 c3 在前,c2 在后)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c5 = 'a5' ORDER BY c3, c2;

說明:用到了 c1 一個索引,但是之后的ORDER BY 是 c3 在前,c2 在后,這就相當於是直接 ORDER BY c3,於是,中間 c2 斷掉了,出現 Using filesort!此 Case 和 Case#11 效果差不多,都是索引中斷了一個中間兄弟。

Case#14:用到了兩個索引

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2' ORDER BY c2, c3;

說明:查詢字段是 1 2 而排序字段是 2 3,是連續的。

Case#15:用到了兩個索引

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2' AND c5 = 'a5' ORDER BY c2, c3;

說明:比 Case#14 多了一個 c5 的查詢字段,但是對結果無影響。

Case#16:用到了兩個索引

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 = 'a2' AND c5 = 'a5' ORDER BY c3, c2;

說明:ORDER BY c3, c2 居然沒有出現 Using filesort!

原因是:在 WHERE 中,c2 = 'a2' 已經是個常量了,所以 ORDER BY c3, c2 就直接等價於(簡化為)ORDER BY c3,故不會出現 Using filesort。

可以和 Case#13 進行對比,此例和 Case#13 的區別就是在於,多了一個 c2 = 'a2',這就把 c1 c2 c3 給連續起來了,沒有斷掉,故不會出現 Using filesort。

Case#17:用到了一個索引(注意:此例是 GROUP BY)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' GROUP BY c2, c3;

說明:分組必排序,所以 GROUP BY c2, c3 等價於 ORDER BY c2, c3,同時,WHERE 條件中有 c1,所以索引連續,能夠正常被使用上。

Case#18:用到了一個索引(注意:GROUP BY 中的 c3 在前,c2 在后)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' GROUP BY c3, c2;

說明:

  • 能夠用到 c1 這個索引
  • GROUP BY c3, c2 等價於 ORDER BY c3, c2,而之前只有 c1 於是索引斷掉了,所以出現 Using filesort(九死一生)
  • GROUP BY 還需要對結果進行分組,所以產生了 Using temporary(十死無生)

Case#19:用到了兩個索引

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 > 'a2' AND c3 = 'a3';

結果:用到了兩個索引,且type=range

Case#20:用到了三個索引(注意:中間的 c2 是 LIKE 查詢,且%在右邊)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 LIKE 'a2%' AND c3 = 'a3';

結果:和 Case#19 不同的是,此例用到了三個索引,且 type=range,有點難以理解,,,,,,,,,,,,待以后再來補充吧,,TODO

Case#21:用到了一個索引(注意:中間的 c2 是 LIKE 查詢,且%在左邊)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 LIKE '%a2' AND c3 = 'a3';

說明:type=ref 且 key_len=31,只用到了一個索引。也能說明,Like 以 % 開頭時無法使用索引。

Case#22:用到了一個索引(注意:中間的 c2 是 LIKE 查詢,且%在兩邊)

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 LIKE '%a2%' AND c3 = 'a3';

說明:和 Case#21 相同,也只用到了一個索引。

Case#23:用到了三個索引

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c2 LIKE 'a2%a2%' AND c3 = 'a3';

說明:結果和 Case#20 相同

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM