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

MySQL 索引優化實戰:IN/OR 導致全表掃描,UNION ALL 改寫提速 400 倍

     編輯:MySQL 綜合教學

場景還原

  • 表 article:200 萬行,1.3 GB
  • 字段 article_category:已建普通索引
  • 查詢:SELECT * FROM article WHERE article_category = 11 ORDER BY article_id DESC LIMIT 5

優化演進路線圖

階段 1:單值查詢優化 (5s → 0.0027s)

問題:單值 = 查詢耗時 5 秒,說明索引未生效或回表代價大。

方案:建立**覆蓋索引** (Composite Index)

CREATE INDEX idx_cat_id ON article (article_category, article_id);

原理:

  1. 索引鍵 (category, id) 完美匹配 WHERE category=11 ORDER BY id DESC
  2. 查詢列 * 包含非索引列 → 仍需回表,但僅回表 5 行
  3. 避免 filesort,直接按索引順序取前 5

效果:0.0027 秒**,提速 **1800 倍**。

階段 2:多值查詢陷阱 (IN/OR 11s → 0.026s)

問題查詢:

-- IN 寫法
SELECT * FROM article WHERE article_category IN (2,3) ORDER BY article_id DESC LIMIT 5;  -- 11.28s
-- OR 寫法
SELECT * FROM article WHERE article_category=2 OR article_category=3 ORDER BY article_id DESC LIMIT 5;  -- 11.07s

根因:MySQL 優化器對 IN/OR **無法使用索引合併**,退化為**全表掃描 + filesort**。

階段 3:UNION ALL 改寫 (破解 IN/OR 限制)

(
  SELECT * FROM article WHERE article_category = 2 ORDER BY article_id DESC LIMIT 5
)
UNION ALL
(
  SELECT * FROM article WHERE article_category = 3 ORDER BY article_id DESC LIMIT 5
)
ORDER BY article_id DESC LIMIT 5;

效果:0.026 秒**,提速 **430 倍**。

原理解析

寫法執行計畫索引利用掃描行數
IN (2,3)type=ALL (全表掃描)❌200 萬
ORtype=ALL (全表掃描)❌200 萬
UNION ALLtype=ref (索引查找) × 2✅ 覆蓋索引5 + 5 = 10

適用條件與避坑

  • ✅ **覆蓋索引** 必須包含 WHERE 列 + ORDER BY 列 + SELECT 列(或僅回表極少行)
  • ✅ 各分支 LIMIT N 後再 UNION ALL 再 LIMIT N,確保總掃描行數可控
  • ❌ UNION (去重) 會引入臨時表排序,**必須用 UNION ALL**
  • ⚠️ 分支過多 (如 > 10) 時考慮臨時表或應用層拆分
  • ⚠️ MySQL 8.0+ 引入 Index Merge 優化,部分場景 IN/OR 可走索引合併,但覆蓋索引 + UNION ALL 仍是最穩方案

通用改寫模板


-- 原始:WHERE col IN (v1,v2,v3) ORDER BY pk DESC LIMIT N
-- 改寫:
(
  SELECT * FROM tbl WHERE col = v1 ORDER BY pk DESC LIMIT N
)
UNION ALL
(
  SELECT * FROM tbl WHERE col = v2 ORDER BY pk DESC LIMIT N
)
UNION ALL
(
  SELECT * FROM tbl WHERE col = v3 ORDER BY pk DESC LIMIT N
)
ORDER BY pk DESC LIMIT N;

總結

**「覆蓋索引 + UNION ALL 分支限制」** 是 MySQL 處理離散值多條件排序分頁的黃金組合。將 IN/OR 的全表掃描拆解為多次**索引精準定位 + 極少行回表**,從秒級降至毫秒級,且邏輯等價、零業務侵入。

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