MySQL优化器成本记录表
SQL優化器會分析所有可能的執行計劃,選擇成本最低的執行,這種優化器稱之為:CBO(Cost-based Optimizer,基于成本的優化器)。
什么是成本
MySQL執行一個查詢可以有不同的執行方案,它會選擇其中成本最低,或者
說代價最低的那種方案去真正的執行查詢。不過我們之前對成本的描述是非常模
糊的,其實在MySQL中一條查詢語句的執行成本是由下邊這兩個方面組成的:
IO成本
我們的表經常使用的MyISAM、InnoDB存儲引擎都是將數據和索引都存儲到
磁盤上的,當我們想查詢表中的記錄時,需要先把數據或者索引加載到內存中然
后再操作。將索引或者數據以頁為基本單位,從磁盤加載到內存的過程稱為IO成本。
CPU成本
在頁中定位記錄,并且判斷記錄是否滿足搜索條件,對結果集排序等操作稱為CPU成本。
對于InnoDB存儲引擎來說,頁是磁盤和內存之間交互的基本單位,MySQL
規定讀取一個頁面花費的成本默認是1.0,讀取以及檢測一條記錄是否符合搜索
條件的成本默認是 0.2。1.0、0.2 這些數字稱之為成本常數,這兩個成本常數我
們最常用到,當然還有其他的成本常數。
注意,不管讀取記錄時需不需要檢測是否滿足搜索條件,其成本都算是0.2。
那么一頁的數據是多大呢,可以通過下面的命令查看:
mysql> show variables like '%innodb_page_size%'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | innodb_page_size | 16384 | +------------------+-------+ 1 row in set (0.00 sec)成本常數
參考官網:https://dev.mysql.com/doc/refman/5.7/en/cost-model.html
server_cost(server層)
該表提供查詢server常規操作需要使用到的優化器成本估算常量值。
下面是該表中存儲的信息內容。
mysql> show create table mysql.server_cost; +-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | server_cost | CREATE TABLE `server_cost` (`cost_name` varchar(64) NOT NULL,`cost_value` float DEFAULT NULL,`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,`comment` varchar(1024) DEFAULT NULL,PRIMARY KEY (`cost_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 | +-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)mysql> select * from mysql.server_cost; +------------------------------+------------+---------------------+---------+ | cost_name | cost_value | last_update | comment | +------------------------------+------------+---------------------+---------+ | disk_temptable_create_cost | NULL | 2021-08-11 08:50:05 | NULL | | disk_temptable_row_cost | NULL | 2021-08-11 08:50:05 | NULL | | key_compare_cost | NULL | 2021-08-11 08:50:05 | NULL | | memory_temptable_create_cost | NULL | 2021-08-11 08:50:05 | NULL | | memory_temptable_row_cost | NULL | 2021-08-11 08:50:05 | NULL | | row_evaluate_cost | NULL | 2021-08-11 08:50:05 | NULL | +------------------------------+------------+---------------------+---------+ 6 rows in set (0.00 sec)表字段含義
-
cost_name:成本模型中使用的成本估算變量名稱。名稱不區分大小寫。如果Server在讀取此表時未識別成本名稱,則會向錯誤日志寫入警告。
-
cost_value: 成本估算變量值。如果該值不為NULL,則Server將直接使用其用作成本計算。否則,它使用默認估計值(代碼內的編譯默認值)。DBA可以通過更新此列值以影響成本估算。但需要確保指定的是有效值(留意表結構中的字段數據類型),如果Server在讀取此表時發現成本值無效(不正確),則會向錯誤日志寫入警告。如果需要恢復默認值,只需要將此字段設置為NULL值即可,然后執行FLUSH OPTIMIZER_COSTS語句來通知Server重新讀取表中的數據。
-
last_update: 最后一次更新該行記錄的時間。
-
comment: 與成本估算變量相關的描述性信息。
server_cost表擁有主鍵列cost_name,因此不可能出現為某個成本估算變量設置多個值的情況。
常量值含義
-
disk_temptable_create_cost(默認為40.0),disk_temptable_row_cost(默認為1.0): 基于磁盤的內部臨時表(InnoDB或MyISAM)的成本估算常量。增加這些值會增加使用基于磁盤的內部臨時表的成本估計值,查詢優化器在進行成本估算時會偏向于更少使用它,與相應的基于內存的內部臨時表的參數(memory_temptable_create_cost,memory_temptable_row_cost)的缺省值相比,默認值較大。
-
key_compare_cost(默認0.1): 比較索引鍵值記錄的成本常量。增加此值會讓查詢優化器認為查詢較多索引鍵值是昂貴的。因為,查詢計劃會盡量避免文件排序(基于索引的排序)。
-
memory_temptable_create_cost(默認2.0),memory_temptable_row_cost(默認0.2): 基于MEMORY存儲引擎的內部臨時表的成本估算常量。增加這些值會增加使用內部內存臨時表的成本估計值,即會使得優化器偏向于更少使用它。
-
row_evaluate_cost(默認值為0.2): 評估記錄行的成本常量。與讀取較少行的范圍掃描相比,表掃描變得相對昂貴,查詢計劃會偏向于更少使用表掃描。
engine_cost(存儲引擎層)
該表提供查詢針對特定存儲引擎的操作需要使用到的的優化器成本估算常量值。
下面是該表中存儲的信息內容。
mysql> show create table mysql.engine_cost; +-------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | engine_cost | CREATE TABLE `engine_cost` (`engine_name` varchar(64) NOT NULL,`device_type` int(11) NOT NULL,`cost_name` varchar(64) NOT NULL,`cost_value` float DEFAULT NULL,`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,`comment` varchar(1024) DEFAULT NULL,PRIMARY KEY (`cost_name`,`engine_name`,`device_type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 | +-------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)mysql> select * from mysql.engine_cost; +-------------+-------------+------------------------+------------+---------------------+---------+ | engine_name | device_type | cost_name | cost_value | last_update | comment | +-------------+-------------+------------------------+------------+---------------------+---------+ | default | 0 | io_block_read_cost | NULL | 2021-08-11 08:50:05 | NULL | | default | 0 | memory_block_read_cost | NULL | 2021-08-11 08:50:05 | NULL | +-------------+-------------+------------------------+------------+---------------------+---------+ 2 rows in set (0.00 sec)表字段含義
-
engine_name:此成本估算常量適用的存儲引擎的名稱。名稱不區分大小寫。如果該值是缺省值,則表示適用于所有存儲引擎。如果Server在讀取此表時未識別引擎名稱,則會向錯誤日志寫入警告(默認值default除外,這里指的是非法值)。
-
device_type:此成本估算常量適用的設備類型。該列旨在為不同的存儲設備類型指定不同的成本估算常量,例如:為機械硬盤與固態硬盤指定不同的估算常量值。目前該字段未使用,目前的唯一有效值為0。
-
cost_name: 與server_cost表中的相同字段含義相同。
-
cost_value: 與server_cost表中的相同字段含義相同。
-
last_update: 與server_cost表中的相同字段含義相同。
-
comment: 與server_cost表中的相同字段含義相同。
engine_cost表的主鍵包含三列(cost_name,engine_name,device_type),所以這三列組合值必須唯一,不可建多個條目。
常量值含義
-
io_block_read_cost(默認1.0): 從磁盤讀取索引或數據塊的成本。與增加此值時的查詢計劃相比,讀取更多磁盤塊的查詢計劃與讀取更少磁盤塊的查詢計劃相比會被查詢計劃認為更加昂貴。例如:與讀取較少塊的范圍掃描相比,表掃描被認為是昂貴的。
-
memory_block_read_cost(默認1.0): 與io_block_read_cost類似,表示從內存緩沖區中讀取索引或數據塊的估算常量。
如果io_block_read_cost和memory_block_read_cost值不同,則執行計劃可能會在相同查詢的兩次運行時發現執行發生了變化(例如: 執行計劃不同或者執行時間不同)。例如:假設內存訪問的成本低于磁盤訪問的成本。在這種情況下,在服務器啟動時還未完成將數據讀入緩沖池之前與之后,兩次執行相同的查詢您可能會得到不同的計劃。
對io_block_read_cost和memory_block_read_cost參數的更改可能會為查詢計劃帶來收益,例如: 在所有其他條件都相同的情況下,將io_block_read_cost值設置為大于memory_block_read_cost的值會使優化程序更喜歡走通過在內存中查詢數據的查詢計劃。
修改成功常數
修改io_block_read_cost的示例信息如下:
mysql> update mysql.engine_cost set cost_value=2.0 where cost_name='io_block_read_cost'; Query OK, 1 row affected (0.04 sec) Rows matched: 1 Changed: 1 Warnings: 0mysql> select * from mysql.engine_cost; +-------------+-------------+------------------------+------------+---------------------+---------+ | engine_name | device_type | cost_name | cost_value | last_update | comment | +-------------+-------------+------------------------+------------+---------------------+---------+ | default | 0 | io_block_read_cost | 2 | 2021-08-16 03:42:36 | NULL | | default | 0 | memory_block_read_cost | NULL | 2021-08-11 08:50:05 | NULL | +-------------+-------------+------------------------+------------+---------------------+---------+ 2 rows in set (0.00 sec)mysql> flush optimizer_costs; Query OK, 0 rows affected (0.00 sec)為innodb引擎單獨插入一行常量值:
mysql> insert into mysql.engine_cost values('InnoDB',0,'io_block_read_cost',2, null, null);Query OK, 1 row affected (0.04 sec)mysql> flush optimizer_costs; Query OK, 0 rows affected (0.00 sec)版本之間的差異
上述展示的成本常量都是基于MySQL5.7.35。
MySQL8中各個成本常量都發生了很大的變化。
mysql> select * from mysql.server_cost; +------------------------------+------------+---------------------+---------+---------------+ | cost_name | cost_value | last_update | comment | default_value | +------------------------------+------------+---------------------+---------+---------------+ | disk_temptable_create_cost | NULL | 2021-08-06 06:32:04 | NULL | 20 | | disk_temptable_row_cost | NULL | 2021-08-06 06:32:04 | NULL | 0.5 | | key_compare_cost | NULL | 2021-08-06 06:32:04 | NULL | 0.05 | | memory_temptable_create_cost | NULL | 2021-08-06 06:32:04 | NULL | 1 | | memory_temptable_row_cost | NULL | 2021-08-06 06:32:04 | NULL | 0.1 | | row_evaluate_cost | NULL | 2021-08-06 06:32:04 | NULL | 0.1 | +------------------------------+------------+---------------------+---------+---------------+ 6 rows in set (0.00 sec)mysql> select * from mysql.engine_cost; +-------------+-------------+------------------------+------------+---------------------+---------+---------------+ | engine_name | device_type | cost_name | cost_value | last_update | comment | default_value | +-------------+-------------+------------------------+------------+---------------------+---------+---------------+ | default | 0 | io_block_read_cost | NULL | 2021-08-06 06:32:04 | NULL | 1 | | default | 0 | memory_block_read_cost | NULL | 2021-08-06 06:32:04 | NULL | 0.25 | +-------------+-------------+------------------------+------------+---------------------+---------+---------------+ 2 rows in set (0.00 sec)總結
以上是生活随笔為你收集整理的MySQL优化器成本记录表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机黑屏不亮,win7休眠后唤醒电脑但
- 下一篇: 如何提高mysql插入速度_mysql技