數據庫索引實效的情況匯總

一、最常見:對索引列做運算 / 函數

? 1. 對索引列使用函數

SELECT * FROM user WHERE YEAR(create_time) = 2024;

原因:

數據庫需要對每一行先算 YEAR(),無法走 B+Tree 有序結構。

? 正確寫法:

SELECT * FROM user 
WHERE create_time >= '2024-01-01' 
AND create_time < '2025-01-01';

? 2. 對索引列做計算

SELECT * FROM user WHERE age + 1 = 20;

等價于:

age = 19

但因為對列做了運算,索引失效。


二、隱式類型轉換

? 字符串列用數字查詢

-- phone 是 varchar
SELECT * FROM user WHERE phone = 13800000000;

數據庫會對 phone 做隱式轉換,索引失效。

? 應寫成:

WHERE phone = '13800000000'

三、LIKE 使用不當

? 左模糊查詢

WHERE name LIKE '%張'

原理:

B+Tree 是按前綴排序的,前面不確定,無法定位范圍。


? 可以使用索引

WHERE name LIKE '張%'

因為是前綴匹配。


四、OR 使用不當

WHERE name = '張三' OR age = 18

如果:

  • name 有索引
  • age 沒索引

?? 可能全表掃描

解決方法:

  • 兩邊都加索引
  • 或改成 UNION

五、違反最左前綴原則(聯合索引)

假設有聯合索引:

index(a, b, c)

? 跳過最左列

WHERE b = 10

索引失效。


? 中間斷裂

WHERE a = 1 AND c = 3

只能用到 a,c 用不上。


?? 遇到范圍查詢會停止匹配

WHERE a = 1 AND b > 2 AND c = 3

用到:

  • a
  • b

但 c 用不到。

因為范圍查詢會截斷索引匹配。


六、!= 或 <> 不等于

WHERE age != 20

MySQL 可能放棄索引,因為選擇性太差。


七、IS NULL / IS NOT NULL

  • IS NULL 通??梢宰咚饕?/li>
  • IS NOT NULL 可能失效(取決于數據分布)

八、數據量太少 / 優(yōu)化器選擇放棄

即使有索引,也可能不用。

例如:

WHERE gender = '男'

如果 90% 都是男:

?? 選擇性太差
?? 優(yōu)化器直接全表掃描更快


九、索引列在表達式右邊

WHERE 10 = age

通常還能用索引,但某些版本優(yōu)化不好。


十、索引列參與字符串拼接

WHERE CONCAT(first_name, last_name) = '張三'

必定失效。


十一、使用 NOT IN

WHERE id NOT IN (1,2,3)

可能不走索引。


十二、覆蓋索引 vs 回表

有時候你以為索引失效,其實:

  • 索引用了
  • 但需要回表
  • 性能依然慢

十三、統(tǒng)計信息過期

MySQL 依賴統(tǒng)計信息決定是否使用索引。

統(tǒng)計失真:

ANALYZE TABLE user;

總結一張腦圖邏輯

索引失效本質原因只有三類:

1?? 破壞了“有序性”

  • 函數
  • 計算
  • 左模糊

2?? 優(yōu)化器覺得不劃算

  • 選擇性太低
  • 數據量小

3?? 違反 B+Tree 使用規(guī)則

  • 最左前綴
  • 范圍截斷

給你一個實戰(zhàn)建議

判斷是否失效,不要猜:

EXPLAIN SELECT ...

看:

  • type 是否為 ALL(全表掃描)
  • key 是否為 NULL
  • rows 掃描行數

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容