MySQL原始碼決議之執行計劃
- MySQL執行計劃介紹
- MySQL執行計劃代碼概覽
- MySQL執行計劃總結
一、MySQL執行計劃介紹
在MySQL中,執行計劃的實作是基于JOIN和QEP_TAB這兩個物件,其中JOIN類表示一個查詢陳述句塊的優化和執行,每個select查詢陳述句(即Query_block物件)在處理的時候,都會被當做JOIN物件,其定義在sql/sql_optimizer.h,
QEP_TAB是Query Execution Plan Table的縮寫,這里的表Table物件主要包含物化表、臨時表、派生表、常量表等,JOIN::optimize()是優化執行器的統一入口,在這里會把一個查詢陳述句塊Query_block最終優化成QEP_TAB,
在MySQL-8.0.22版本之后,又引入訪問方式AccessPath和執行迭代器Iterator物件,再結合JOIN和QEP_TAB物件,最終得到整個決議計劃的執行路徑,
二、MySQL執行計劃代碼概覽
本文主要基于MySQL-8.0.25版本,進行說明,
優化器的入口函式:bool JOIN::optimize(),對應代碼檔案sql/sql_optimizer.cc,
// 主要功能是把一個查詢塊Query_block優化成一個QEP_TAB,得到AccessPath
bool JOIN::optimize() {
...
// 下面主要是為了可以借助INFORMATION_SCHEMA.OPTIMIZER_TRACE表,跟蹤優化器的執行狀態和執行步驟
Opt_trace_context *const trace = &thd->opt_trace;
Opt_trace_object trace_wrapper(trace);
Opt_trace_object trace_optimize(trace, "join_optimization");
trace_optimize.add_select_number(Query_block->select_number);
Opt_trace_array trace_steps(trace, "steps");
...
// 視窗函式裝配優化
if (has_windows && Window::setup_windows2(thd, m_windows))
...
// 拷貝Query_block上的條件副本到JOIN結構關聯的成員物件,為后續優化做準備
if (Query_block->get_optimizable_conditions(thd, &where_cond, &having_cond))
...
// 統計抽象語法樹中的葉節點表,其中leaf_tables是在Query_block::setup_tables中進行裝配
tables_list = Query_block->leaf_tables;
...
// 磁區裁剪
if (Query_block->partitioned_table_count && prune_table_partitions()) {
...
// 嘗試把聚合函式COUNT()、MIN()、MAX()對應的值,替換成常量
if (optimize_aggregated_query(thd, Query_block, *fields, where_cond,
&outcome)) {
...
// 采用超圖演算法生成執行計劃,注意超圖演算法通過set optimizer_switch="hypergraph_optimizer=on"方式啟用
if (thd->lex->using_hypergraph_optimizer) {
FindBestQueryPlan(thd, Query_block, /*trace=*/nullptr);
// 如果Join優化器是超圖演算法,處理結束直接回傳
return false;
}
...
下面代碼主要涉及Join優化器連接方式為左深樹的情況,主要用到join_tab陣列來進行組織關聯
根據代價計算表的連接方式,核心函式make_join_plan(),實作非常復雜,比較關鍵的函式是bool Optimize_table_order::choose_table_order()
其主要思想是通過貪婪搜索Optimize_table_order::greedy_search,根據最小的連接代價,進行有限的窮舉搜索(細節參考Optimize_table_order::best_extension_by_limited_search)
最終找到近似最優解的連接排列組合
if (make_join_plan()) {
...
// 陳述句塊謂詞條件下推,提升過濾性能
if (make_join_Query_block(this, where_cond)) {
...
// 優化order by/distinct陳述句
if (optimize_distinct_group_order()) return true;
...
// 分配QEP_TAB陣列
if (alloc_qep(tables)) return (error = 1); /* purecov: inspected */
...
// 執行計劃細化,優化子查詢和半連接的情況,具體策略可以參考mariadb的檔案:
// https:// mariadb.com/kb/en/optimization-strategies/
// 關鍵代碼是setup_semijoin_dups_elimination,主要對半連接關聯的策略進行裝配
if (make_join_readinfo(this, no_jbuf_after))
...
// 為處理group by/order by創建開辟臨時表空間
if (make_tmp_tables_info()) return true;
...
// 生成訪問方式AccessPath,供后續迭代器Iterator訪問使用
create_access_paths();
...
return false;
}
三、MySQL執行計劃總結
MySQL的執行計劃是整個資料庫最核心的模塊,其代碼也在不斷地迭代更新程序中,執行計劃中優化器的好壞和背后的搜索策略、數學模型緊密相關,MySQL支持的搜索策略有窮舉搜索、貪婪搜索,對應的Join優化器有左深樹演算法和超圖演算法,整個優化程序主要是基于CBO策略進行優化,
執行計劃運行的程序,實際上就是一個動態規劃的程序,這個程序的優劣,快慢決定了MySQL和主流商業資料庫的差距,只有深入地理解MySQL優化器的運行原理,才能幫助我們積極有效地探索更高性能優化的可能,
最后由于筆者知識水平有限,疏漏之處,還望斧正,
Enjoy GreatSQL ??
文章推薦:
面向金融級應用的GreatSQL正式開源
Changes in GreatSQL 8.0.25 (2021-8-18)
MGR及GreatSQL資源匯總
GreatSQL MGR FAQ
在Linux下原始碼編譯安裝GreatSQL/MySQL
關于 GreatSQL
GreatSQL是由萬里資料庫維護的MySQL分支,專注于提升MGR可靠性及性能,支持InnoDB并行查詢特性,是適用于金融級應用的MySQL分支版本,
Gitee:
https://gitee.com/GreatSQL/GreatSQL
GitHub:
https://github.com/GreatSQL/GreatSQL
Bilibili:
https://space.bilibili.com/1363850082/favlist
微信&QQ群:
QQ群:533341697
微信群:可搜索添加GreatSQL社區助手微信好友,發送驗證資訊“加群”加入GreatSQL/MGR交流微信群
GreatSQL社區助手:wanlidbc
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/501227.html
標籤:其他
上一篇:Redis 安裝與使用
下一篇:Redis 定長佇列的探索和實踐
