like使用索引如何避免失效


1 准備數據

1.1 建表

  1. DROP TABLE IF EXISTS staff;
  2. CREATE TABLE IF NOT EXISTS staff (
  3. id INT PRIMARY KEY auto_increment,
  4. name ),
  5. age INT,
  6. pos ) COMMENT '職位',
  7. salary ,)
  8. );

1.2 插入數據

  1. , );

2 測試&Explain分析

2.1 有索引的情況下%的影響(提出問題)

2.1.1 建立索引

  1. CREATE INDEX idx_nameAgePos ON staff(name, age, pos);

2.1.2 測試&Explain分析

Case#1:兩邊都是%

  1. EXPLAIN SELECT * FROM staff WHERE name LIKE '%Alice%';

結果:type=all,全表掃描

Case#2:左邊是%

  1. EXPLAIN SELECT * FROM staff WHERE name LIKE '%Alice';

結果:type=all,全表掃描

Case#3:右邊是%

  1. EXPLAIN SELECT * FROM staff WHERE name LIKE 'Alice%';

結果:type=range,效果還可以。

對上面三個例子的總結:

  • 都是 SELECT *
  • %在左邊,即使有索引,也會失效
  • 只有當%在右邊時,才會生效

但問題是,生產環境中,就是要支持模糊查詢(%在右邊是不夠的),一定要兩邊都是%來查詢,這可咋辦?

2.2 無索引情況下的查詢匯總

2.2.1 刪除索引

  1. DROP INDEX idx_nameAgePos ON staff;

2.2.2 測試&Explain分析(主要為了和 2.3.2 節做對比測試)

Case#4:查詢Id

  1. EXPLAIN SELECT id FROM staff WHERE name LIKE '%Alice%';

Case#5:查詢name

  1. EXPLAIN SELECT name FROM staff WHERE name LIKE '%Alice%';

Case#6:查詢age

  1. EXPLAIN SELECT age FROM staff WHERE name LIKE '%Alice%';

Case#7:查詢 id & name

  1. EXPLAIN SELECT id, name FROM staff WHERE name LIKE '%Alice%';

Case#8:查詢 name & age

  1. EXPLAIN SELECT name, age FROM staff WHERE name LIKE '%Alice%';

Case#9:查詢 id & name & age

  1. EXPLAIN SELECT id, name, age FROM staff WHERE name LIKE '%Alice%';

Case#10:查詢 id & name & age & salary (提示:salary 不在索引列中,后面會用上)

  1. EXPLAIN SELECT id, name, age, salary FROM staff WHERE name LIKE '%Alice%';

Case#11:查詢 *

  1. EXPLAIN SELECT * FROM staff WHERE name LIKE '%Alice%';

從 Case#4 到 Case#11 可以看出,在沒有索引的情況下,兩邊都使用 % 來查詢,不管想查詢哪個字段(包括查詢Id),全部都是全表掃描。

2.3 有索引情況下的查詢匯總

2.3.1 建立索引

  1. CREATE INDEX idx_nameAgePos ON staff(name, age, pos);

2.3.2 測試&Explain分析

IndexCase#4:查詢Id

  1. EXPLAIN SELECT id FROM staff WHERE name LIKE '%Alice%';

結果:使用上了索引(因為 name 有索引,同時查詢的 Id 是主鍵肯定也有索引)

IndexCase#5:查詢name

  1. EXPLAIN SELECT name FROM staff WHERE name LIKE '%Alice%';

結果:使用上了索引(因為查詢條件和查詢字段都是有索引的 name)

IndexCase#6:查詢age

  1. EXPLAIN SELECT age FROM staff WHERE name LIKE '%Alice%';

結果:使用上了索引(因為查詢條件的 name 以及查詢字段的 age 都有索引)

IndexCase#7:查詢 id & name

  1. EXPLAIN SELECT id, name FROM staff WHERE name LIKE '%Alice%';

結果:使用上了索引(因為查詢條件的 name 以及查詢字段的 id & name 都有索引)

IndexCase#8:查詢 name & age

  1. EXPLAIN SELECT name, age FROM staff WHERE name LIKE '%Alice%';

結果:使用上了索引(因為查詢條件的 name 以及查詢字段的 name & age 都有索引)

IndexCase#9:查詢 id & name & age

  1. EXPLAIN SELECT id, name, age FROM staff WHERE name LIKE '%Alice%';

結果:使用上了索引(因為查詢條件的 name 以及查詢字段的 id & name & age 都有索引)

IndexCase#10:查詢 id & name & age & salary (提示:salary 不在索引列中)

  1. EXPLAIN SELECT id, name, age, salary FROM staff WHERE name LIKE '%Alice%';

結果:沒有索引,type=all,全表掃描!(因為查詢字段中多了個 salary 而 salary 不在索引列中)

IndexCase#11:查詢 *

  1. EXPLAIN SELECT * FROM staff WHERE name LIKE '%Alice%';

結果:沒有索引,type=all,全表掃描!(因為 * 包含 salary 而 salary 不在索引列中)

通過 IndexCase#4 到 IndexCase#11 可以看出,當真的需要兩邊都使用%來模糊查詢時,只有當這個作為模糊查詢的條件字段(例子中的name)以及所想要查詢出來的數據字段(例子中的 id & name & age)都在索引列上時,才能真正使用索引,否則,索引失效全表掃描(比如多了一個 salary 字段)。我想,這應該就是 ‘覆蓋索引(索引覆蓋)’ 的本質吧。同時,這也能很好的證實 “盡量避免SELECT * 而是一一羅列出所需要查詢的字段” 的道理吧,因為,搞不好 SELECT * 就多了一個字段,就導致了全表掃描。

3 結論

LIKE以%開頭會導致索引失效;使用覆蓋索引解決之


免責聲明!

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



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