當執行如下 SQL:
SELECT * FROM users WHERE id = 1;
在數據庫內部,其實會經歷多個復雜且有序的階段。以下是 MySQL(InnoDB 引擎)中 SQL 查詢語句從發送到結果返回的完整執行流程。
客戶端連接階段
- 客戶端(如 JDBC、MySQL Shell)通過 TCP 與 MySQL 服務器建立連接。
- 連接器模塊完成身份認證(用戶名/密碼)、權限校驗。
- 若使用連接池,連接可能已被復用。
語法分析階段(Parser)
1. 詞法分析(Lexical Analysis)
- 將 SQL 字符串拆解成關鍵字、標識符、操作符等 Token。
- 例子:
SELECT
,*
,FROM
,users
,WHERE
,id
,=
,1
2. 語法分析(Syntax Analysis)
- 依據 SQL 語法規則生成抽象語法樹(AST)。
- 若語法不合法,此階段拋出語法錯誤。
預處理階段(Preprocessor)
- 驗證表/字段是否存在。
- 檢查當前用戶是否有訪問權限。
- 解析字段別名、函數等表達式。
- 確定查詢涉及的表和列。
- 最終輸出邏輯查詢結構。
查詢優化階段(Optimizer)
優化器根據預處理階段的語義結構生成最優執行計劃(Execution Plan)。
1. 訪問路徑選擇
- 使用 索引掃描 還是 全表掃描?
- 是否走覆蓋索引,是否需要回表?
2. 連接順序優化(Join Order)
- 對多表 JOIN,決定訪問順序與連接方法(如 Nested Loop、Hash Join)。
3. 成本估算(Cost Estimation)
- 評估每種執行方式的代價(IO 次數、內存使用等)。
- 選擇代價最小的執行路徑。
查詢執行階段(Executor)
執行器根據優化器生成的執行計劃與存儲引擎交互,完成數據訪問。
執行器主要職責:
- 調用引擎接口訪問表和索引。
- 進行 WHERE 過濾、JOIN、聚合、排序、分組等操作。
- 構造并返回最終結果集。
存儲引擎訪問階段(以 InnoDB 為例)
MySQL 使用插件式存儲引擎架構。以 InnoDB 為例:
- 數據頁首先嘗試從 Buffer Pool(緩沖池)中讀取。
- 若不在緩沖池,則從磁盤讀取并加入緩沖池。
- 使用 B+ 樹索引定位記錄。
- 如果為覆蓋索引(索引包含查詢列),可避免回表。
- 對于非索引字段,需根據主鍵“回表”查找。
結果返回階段
- 執行器生成的結果集通過 MySQL 協議格式化。
- 數據從服務器通過網絡傳輸返回給客戶端。
- 客戶端解析并展示結果。
日志與事務支持(InnoDB)
雖然 SELECT 查詢本身不會寫入日志,但其他 SQL 會涉及以下機制:
- Undo Log:支持事務回滾、MVCC。
- Redo Log:保證事務持久化(WAL機制)。
- Binlog:記錄變更操作,用于主從復制和恢復。
注:查詢語句可能間接使用 undo log(如 MVCC)。
SQL 執行流程圖
使用 EXPLAIN 查看執行計劃
EXPLAIN SELECT * FROM users WHERE id = 1;
查看字段含義:
id
: 查詢標識select_type
: 查詢類型(SIMPLE/PRIMARY等)table
: 訪問的表type
: 連接類型(ALL、index、range、ref、const 等)key
: 使用的索引rows
: 掃描的行數Extra
: 是否使用臨時表、排序、是否回表等信息
查詢性能影響因素
影響因素 | 說明 |
---|---|
是否走索引 | 非索引字段將觸發全表掃描 |
是否回表 | 二級索引查詢非索引字段時需根據主鍵回表 |
連接數與并發 | 并發高時,CPU/IO/鎖資源緊張 |
查詢緩存 | MySQL 8.0 起已廢棄 |
臨時表與排序 | ORDER BY / GROUP BY 可能觸發文件排序與臨時表 |
網絡延遲 | 大結果集網絡傳輸慢 |
總結
一條 SQL 查詢的完整內部執行流程如下:
- 客戶端連接 → 建立連接并認證
- 解析 SQL → 詞法/語法分析生成語法樹
- 預處理 → 驗證權限與對象合法性
- 優化器選擇最優執行計劃
- 執行器執行 SQL 邏輯
- 存儲引擎讀取數據
- 返回結果集給客戶端