首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 查詢優化核心工具與索引實戰:EXPLAIN 深度解析

     編輯:MySQL 資料庫相關知識

優化三板斧:工具、索引、執行計劃

MySQL 優化入門必掌握:EXPLAIN、SHOW VARIABLES、SHOW STATUS、SHOW PROCESSLIST。大表禁用 GROUP BY(臨時表+文件排序風險極大)。索引設計遵循「少而精」原則。

一、索引使用邊界

✅ 能用上索引的操作符

>, >=, =, <, <=, IS NULL, BETWEEN, IN(), LIKE 'prefix%'

❌ 不會使用索引的情況

  • 優化器估計全表掃描更快(如匹配行數 > 表總行數 20-30%)
  • LIKE '%suffix'、LIKE '%middle%' 導致索引失效
  • 隱式類型轉換:WHERE varchar_col = 123(數字比較字符串)
  • 索引列參與運算:WHERE YEAR(date_col) = 2023、WHERE col1 + 1 = 10
  • 聯合索引未遵循最左前綴原則

二、EXPLAIN 逐列深度解讀

列含義關鍵判讀
id查詢序號相同 id 從上往下執行;不同 id 值大優先
select_type查詢類型SIMPLE(無子查詢/UNION)、PRIMARY(最外層)、SUBQUERY、DERIVED(派生表/子查詢 FROM)、UNION、UNION RESULT
table訪問的表別名或 /
partitions匹配的分區分區表才顯示
type訪問類型(核心!)從優到劣:system > const > eq_ref > ref > range > index > ALL
possible_keys理論可用索引為空 → 無索引可用,需檢查 WHERE/JOIN 條件列
key實際使用索引NULL → 全表掃描!可用 FORCE/USE/IGNORE INDEX 干預
key_len索引鍵長度越短越好(不損失精度前提下),推斷聯合索引用了幾列
ref索引對比的列/常量const、func、NULL、列名
rows預估掃描行數越小越好,結合 type 判斷效率
filtered按條件過濾後剩餘比例%越接近 100 越好
Extra額外信息(核心!)見下表

type 類型效率階梯詳解

  1. system:表僅 1 行(系統表特例)
  2. const:主鍵/唯一索引等值查詢,最多 1 行,優化器視為常量
  3. eq_ref:聯接時,前表每行在後表精確匹配 1 行(主鍵/唯一索引),最佳聯接類型
  4. ref:非唯一索引等值查詢/聯接,前表每行匹配多行,**匹配行數越少越好**
  5. range:索引範圍掃描(>, <, >=, <=, BETWEEN, IN, LIKE 'prefix%')
  6. index:全索引掃描(比 ALL 好,因索引通常小於數據)
  7. ALL:全表掃描,**極力避免**

Extra 欄位關鍵值解讀

值含義嚴重程度對策
Using filesort需額外排序操作(無索引支持 ORDER BY/GROUP BY)🔴 嚴重加索引匹配排序列、避免跨表排序
Using temporary需建立臨時表(GROUP BY/DISTINCT/ORDER BY 列不一致)🔴 嚴重優化索引、避免 SELECT *、調大 tmp_table_size
Using index覆蓋索引:僅訪問索引樹,無需回表🟢 極佳設計覆蓋索引,SELECT 列 ⊆ 索引列
Using whereServer 層過濾(存儲引擎返回後再篩選)🟡 正常/警示若 type=ALL/index 且無 Using index,說明全表掃描後過濾
Using index conditionICP (Index Condition Pushdown):存儲引擎層過濾🟢 優秀MySQL 5.6+ 自動啟用,需索引包含 WHERE 列
Range checked for each record無理想索引,逐行嘗試決定用哪個索引🔴 極差重設計索引
Distinct / Not exists優化後提前終止掃描🟢 正常—

三、實戰優化案例

案例 1:覆蓋索引消除回表

-- 原查詢
SELECT id, name FROM users WHERE status=1 AND create_time > '2023-01-01';
-- EXPLAIN: type=ref, key=idx_status, rows=50000, Extra=Using where

-- 優化:建立覆蓋索引
ALTER TABLE users ADD INDEX idx_status_ct_name (status, create_time, name);
-- EXPLAIN: type=range, key=idx_status_ct_name, rows=200, Extra=Using index

案例 2:避免 filesort

-- 原查詢
SELECT * FROM orders WHERE user_id=100 ORDER BY created_at DESC LIMIT 10;
-- EXPLAIN: type=ref, key=idx_user_id, rows=5000, Extra=Using where; Using filesort

-- 優化:聯合索引匹配 WHERE + ORDER BY
ALTER TABLE orders ADD INDEX idx_uid_created (user_id, created_at DESC);
-- EXPLAIN: type=ref, key=idx_uid_created, rows=10, Extra=Using index

案例 3:強制索引干預優化器誤判

SELECT * FROM t1 FORCE INDEX (idx_a) WHERE a=1 AND b=2;
-- 僅在確信優化器選錯(如統計信息過期)時使用,慎用 IGNORE INDEX

四、SHOW PROCESSLIST:實時診斷利器

SHOW FULL PROCESSLIST;
-- 關鍵列:
-- Id, User, Host, db, Command, Time, State, Info
-- 關注:Time 長、State='Sending data'/'Copying to tmp table'/'Locked'、Info 為慢查詢 SQL
  • 發現長事務、鎖等待、未提交事務
  • 配合 SHOW ENGINE INNODB STATUS 死鎖分析
  • 定期抓取快照建立基線

五、優化口訣

  1. EXPLAIN 先行,不盲目加索引
  2. type 至少 ref,杜絕 ALL/index
  3. Extra 無紅燈,拒絕 filesort/temporary
  4. 覆蓋索引妙,回表開銷全消
  5. 最左前綴記心頭,聯合索引不亂建
  6. 大表不 Group By,分庫分表或應用層聚合

MySQL 優化無銀彈,但 EXPLAIN 是唯一通用的「X 光機」。讀懂執行計劃,理解存儲引擎行為,優化就有了確定性方向。

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