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

MySQL 優化器索引與 JOIN 順序選擇全流程剖析:Range Analysis、貪婪搜索、Bad Case 構造

     編輯:MySQL 綜合教學

案例 SQL

EXPLAIN SELECT *
FROM employee AS A, department AS B
WHERE A.LastName = 'zhou'
  AND B.DepartmentID = A.DepartmentID
  AND B.DepartmentName = 'TBX';

表結構:

  • employee:索引 IND_L_D(LastName)、IND_DID(DepartmentID)
  • department:索引 IND_D(DepartmentID)、IND_DN(DepartmentName)

優化器核心流程

1. Range Analysis(範圍分析)

評估單表過濾條件的「過濾行數」:

  • A.LastName='zhou' → found_records = 51
  • B.DepartmentName='TBX' → found_records = 1

InnoDB 通過 records_in_range 採樣索引頁估算,**無直方圖時精度有限**。

2. JOIN 順序枚舉:貪婪搜索

MySQL 僅支援 Left-Deep Tree**,按 found_records 升序排表(B 先於 A),再枚舉所有順序:

順序 1:B → A(最優)

  • B 為首表:只能用 IND_DN(DepartmentName='TBX'),成本 1.2(IO=1)。
  • A 為次表:可選 IND_L_D(LastName='zhou',成本 25.2)或 IND_DID(B.DepartmentID=A.DepartmentID,成本 1.2)。
  • 選 IND_DID,**總成本 2.4**。

順序 2:A → B(剪枝)

  • A 為首表:只能用 IND_L_D,成本 25.2,**已超過當前最優 2.4,直接剪枝**。

3. 最終執行計劃

+----+-------------+-------+------+-----------------+---------+---------+---------------------+------+-------------+
| id | select_type | table | type | possible_keys   | key     | key_len | ref                 | rows | Extra       |
+----+-------------+-------+------+-----------------+---------+---------+---------------------+------+-------------+
| 1  | SIMPLE      | B     | ref  | IND_D,IND_DN    | IND_DN  | 62      | const               | 1    | Using where |
| 1  | SIMPLE      | A     | ref  | IND_L_D,IND_DID | IND_DID | 5       | test.B.DepartmentID | 1    | Using where |
+----+-------------+-------+------+-----------------+---------+---------+---------------------+------+-------------+

Bad Case 構造:統計信息誤導優化器

構造數據:

  • department 中 DepartmentID=27760 有 1010 行,其中 DepartmentName='TBX' 只有 10 行。
  • employee 中 LastName='zhou' 僅 1 行,DepartmentID=27760。

EXPLAIN 結果:

| table | type | key     | rows | Extra       |
| A     | ref  | IND_L_D | 1    | Using where |
| B     | ref  | IND_D   | 1    | Using where |

優化器選 A → B,走 IND_D 掃描 1010 行再過濾 DepartmentName='TBX',**實際應走 IND_DN 只掃 10 行**。

根因與對策

根因對策
InnoDB 無直方圖,依賴索引採樣估算選擇率MySQL 8.0 引入 ANALYZE TABLE ... UPDATE HISTOGRAM,手動建立直方圖
關聯列數據傾斜(少數值佔多數行)建立復合索引 (DepartmentName, DepartmentID) 讓優化器直接命中
統計信息過期定期 ANALYZE TABLE 或啟用 innodb_stats_persistent=ON + innodb_stats_auto_recalc=ON
優化器剪枝過早(prune_level)複雜查詢可暫時 SET optimizer_prune_level=0 觀察完整枚舉

總結

MySQL 優化器以「單表過濾行數估算 + Left-Deep Tree 貪婪枚舉 + 成本模型」為核心。**統計信息準確性是成本模型的命門**,生產環境務必建立直方圖、持久化統計、復合索引覆蓋高頻關聯,將優化器引向最優路徑。

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