首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 索引缺點與使用注意事項:空值、短索引、排序、LIKE、運算與 NOT IN 陷阱

     編輯:MySQL 綜合教學

索引雖能大幅提升查詢效能,但並非銀彈。本文系統剖析索引的三大固有缺點、六大使用陷阱與避坑指南,助你在享受索引紅利的同時,避開效能反而下降的陷阱。

索引三大固有缺點

缺點影響緩解策略
降低寫入效能INSERT/UPDATE/DELETE 需同步維護索引樹,索引越多寫入越慢讀寫比低的表慎加索引;大量匯入時先刪索引、匯入後重建
佔用磁碟空間每個索引對應一棵 B+ 樹,複合索引、長字串索引膨脹快用前綴索引、避免過度索引、定期 OPTIMIZE TABLE 整理碎片
增加優化器負擔優化器需評估更多索引選擇,統計資訊不準時可能選錯索引定期 ANALYZE TABLE 更新統計;必要時用 FORCE INDEX 指定

六大使用陷阱與解決方案

1. 索引不包含 NULL 值

現象: 含 NULL 的行不會出現在索引中;複合索引任一欄為 NULL,整行不入該索引。
影響: WHERE col IS NULL 無法用索引;COUNT(col) 不統計 NULL。
解決:

  • 欄位定義 NOT NULL DEFAULT '' 或 0
  • 必須查 NULL 時:WHERE col IS NULL 改用 WHERE IFNULL(col, '') = '' (仍可能不走索引),或建立輔助欄位 is_col_null TINYINT 索引

2. 善用短索引 (前綴索引)

原則: 長字串欄位 (VARCHAR/CHAR/TEXT/BLOB) 指定前綴長度建索引。
範例: CHAR(255) 欄位,前 10-20 字元區分度已高 → INDEX idx_prefix (col(10))
效益: 索引體積 ↓ 50-90%、I/O ↓、緩存命中率 ↑、插入更新速度 ↑

3. 索引列排序與 ORDER BY 衝突

鐵律: MySQL 單表查詢只能使用一個索引。
場景: WHERE a=1 ORDER BY b,若用 INDEX(a) 則 ORDER BY b 需 filesort;若用 INDEX(b) 則 WHERE a=1 全掃。
解決:

  • 建立複合索引 INDEX(a, b),同時滿足過濾與排序
  • 若無法建複合索引,讓資料庫按預設排序 (通常為主鍵序),應用層排序
  • 避免多欄位排序 ORDER BY a, b,必要時建 INDEX(a, b)

4. LIKE 語句操作陷阱

模式索引替代方案
LIKE 'abc%'✅ 生效—
LIKE '%abc%'❌ 失效全文索引 FULLTEXT / Elasticsearch
LIKE '%abc'❌ 失效反轉欄位存儲 + 前綴匹配 / 搜尋引擎

5. 欄位上進行運算導致索引失效

錯誤範例:


SELECT * FROM users WHERE YEAR(create_time) = 2024;
SELECT * FROM inventory WHERE amount / 7 < 24;

正確重寫:


SELECT * FROM users WHERE create_time >= '2024-01-01' AND create_time < '2025-01-01';
SELECT * FROM inventory WHERE amount < 24 * 7;

核心原則: 將運算移至等號右側常數,保持欄位「乾淨」。

6. 避免 NOT IN 和 <> 操作

  • NOT IN 含 NULL 會導致整體判斷為 UNKNOWN (視為 FALSE),且常觸發全掃
  • <>、!= 範圍過大,優化器傾向全掃
  • 替代: NOT EXISTS、LEFT JOIN ... WHERE t2.id IS NULL、NOT BETWEEN (有範圍時)

進階避坑指南

隱含類型轉換


-- 錯誤:VARCHAR 欄位與數字比較
WHERE phone = 13800138000  -- 索引失效,全表掃描

-- 正確:字串比字串
WHERE phone = '13800138000'

複合索引欄位順序錯誤


-- 查詢:WHERE a=1 AND b>2 ORDER BY c
-- 錯誤索引:INDEX(b, a, c) -- 範圍欄位 b 在前,a、c 用不到
-- 正確索引:INDEX(a, b, c) -- 等值 a 在前,範圍 b 次之,排序 c 最後

覆蓋索引未包含 SELECT 欄位


-- 索引:INDEX(a, b)
-- 查詢:SELECT a, b, c FROM t WHERE a=1 -- 需回表取 c
-- 優化:INDEX(a, b, c) -- 覆蓋索引,Extra: Using index

索引維護最佳實踐

  1. 定期 ANALYZE TABLE:更新統計資訊,確保優化器決策準確
  2. 監控慢查詢日誌:long_query_time=1,配合 pt-query-digest 分析
  3. 定期檢查重複/冗餘索引:pt-duplicate-key-checker 或人工審視
  4. 大表索引變更用 Online DDL:MySQL 5.6+ ALGORITHM=INPLACE 避免鎖表
  5. 測試環境驗證:上線前用生產級資料量跑 EXPLAIN 與實測

總結

索引是「換空間換時間、換寫入換讀取」的權衡藝術。掌握「不存 NULL、用短索引、避免函數運算、拒絕 %開頭 LIKE、謹慎 NOT IN、警惕隱含轉換」六大鐵律,配合定期統計更新與慢查詢分析,才能讓索引持續發揮正效益,而非成為效能負債。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved