MySQL通過影響查詢計劃評估方式的系統變量、可切換優化、優化器和索引提示以及優化器成本模型提供優化器控制。
服務器在column_statistics數據字典表中維護有關列值的直方圖統計信息(請參閱第10.9.6節“Optimizer統計信息”)。與其他數據字典表一樣,用戶無法直接訪問此表。相反,您可以通過查詢information_SCHEMA來獲取直方圖信息。COLUMN_STATISTICS,它被實現為數據字典表上的視圖。您還可以使用ANALYZE TABLE語句執行直方圖管理。
1.控制查詢計劃評估
????????查詢優化器的任務是找到執行SQL查詢的最佳計劃。由于“好”和“壞”計劃之間的性能差異可能是幾個數量級(即秒與小時甚至天),因此大多數查詢優化器,包括MySQL的查詢優化器,都會在所有可能的查詢評估計劃中或多或少地搜索最優計劃。
????????對于聯接查詢,MySQL優化器調查的可能計劃的數量隨著查詢中引用的表的數量呈指數級增長。對于少量的表(通常少于7到10個),這不是問題。然而,當提交更大的查詢時,用于查詢優化的時間很容易成為服務器性能的主要瓶頸。
????????一種更靈活的查詢優化方法使用戶能夠控制優化器在搜索最佳查詢評估計劃時的詳盡程度。一般的想法是,優化器調查的計劃越少,編譯查詢所花費的時間就越少。另一方面,由于優化器跳過了一些計劃,它可能無法找到最佳計劃。
優化器相對于其評估的計劃數量的行為可以使用兩個系統變量進行控制:
optimizer_prune_level變量告訴優化器根據每個表訪問的行數估計跳過某些計劃。
我們的經驗表明,這種“有根據的猜測”很少會錯過最佳計劃,并可能大大減少查詢編譯時間。這就是為什么默認情況下此選項處于啟用狀態(optimizer_prune_level=1)。
但是,如果您認為優化器錯過了更好的查詢計劃,則可以關閉此選項(optimizer_prune_level=0),這樣可能會導致查詢編譯耗時更長。
請注意,即使使用了這種啟發式方法,優化器仍然會探索大致指數數量的計劃。
optimizer_search_depth變量告訴優化器應該在每個不完整計劃的“未來”中將查看的深度,以評估是否應該進一步擴展。
optimizer_search_depth的值越小,查詢編譯時間就越小。
例如,如果optimizer_search_depth接近查詢中的表數,則具有12個、13個或更多表的查詢
可能很容易需要數小時甚至數天才能編譯。
同時,如果使用等于3或4的optimizer_search_depth進行編譯,則優化器可以在不到一分鐘的時間內對同一查詢進行編譯。
如果您不確定optimizer_search_depth的合理值是多少,可以將該變量設置為0,以告訴優化器自動確定該值。
2.可切換優化
優化器開關系統變量可以控制優化器的行為。
它的值是一組標志,每個標志的值為on或off,以指示相應的優化器行為是啟用還是禁用。
此變量具有全局值和會話值,可以在運行時更改。
全局默認值可以在服務器啟動時設置。
要查看當前的優化器標志集,請選擇變量值:
mysql> SELECT @@optimizer_switch\G
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,skip_scan=on,hash_join=on,subquery_to_derived=off,prefer_ordering_index=on,hypergraph_optimizer=off,derived_condition_pushdown=on
1 row in set (0.00 sec)
?要更改optimizer_switch的值,請指定一個由一個或多個命令的逗號分隔列表組成的值:
SET [GLOBAL|SESSION] optimizer_switch='command[,command]...';
每個命令值都應具有下表所示的其中一種形式。
命令 | 意義 |
---|---|
default | 將每個優化重置為其默認值 |
| 將命名優化設置為其默認值 |
| 禁用命名優化 |
| 啟用命名優化 |
值中命令的順序無關緊要,盡管默認命令會首先執行(如果存在)。
將opt_name標志設置為default會將其設置為on或off中的默認值。
不允許在值中多次指定任何給定的opt_name,這會導致錯誤。
值中的任何錯誤都會導致賦值失敗并出現錯誤,使優化器開關的值保持不變。
以下列表描述了按優化策略分組的允許的opt_name標志名稱:
2.1 批處理密鑰訪問標志
batched_key_access(默認關閉)
控制BKA聯接算法的使用。
batched_key_access在設置為on時要有任何效果,mrr標志也必須為on。
目前,mrr的成本估計過于悲觀。因此,也有必要關閉mrr_cost_based以使用BKA。
有關更多信息,請參閱“塊嵌套循環和批處理Key訪問連接”。
【MySQL精通之路】SQL優化(1)-查詢優化(12)-塊嵌套循環和批處理Key訪問聯接-CSDN博客
2.2 塊嵌套循環標志
block_nested_roop(默認啟用)
控制BNL聯接算法的使用。
在MySQL 8.0.18及更高版本中,這也控制了散列聯接的使用,BNL和NO_BNL優化器提示也是如此。
在MySQL 8.0.20及更高版本中,從MySQL服務器中刪除了塊嵌套循環支持,該標志僅控制散列聯接的使用,引用的優化器提示也是如此。
有關更多信息,請參閱“塊嵌套循環和批處理Key訪問連接”。
【MySQL精通之路】SQL優化(1)-查詢優化(12)-塊嵌套循環和批處理Key訪問聯接-CSDN博客
2.3 條件篩選標志
condition-fanout-filter(默認打開)
控制條件篩選的使用。
【MySQL精通之路】SQL優化(1)-查詢優化(13)-條件過濾-CSDN博客
未完待續。。。