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优化器成本记录表相关推荐
- MySQL优化器如何预估查询成本
MySQL有哪些查询成本 MySQL 执行一个查询可以有不同的执行方案.在我们开发过程中,所有写过的sql语句都会丢给MySQL端的优化器.由优化器判断并选择其中成本最低,或者说代价最低的那种方案去真 ...
- MySQL优化器:index merge介绍
在MySQL官方手册上,关于index merge的介绍非常非常少.甚至还有不少误导的地方,这次把5.1版本关于此类优化处理的代码细看了一遍,以案例的方式介绍了各种实用index merge访问类型的 ...
- Mysql 优化器内部JOIN算法hash join On-Disk Hash Join Grace Hash Join Hybrid hash join过程详解
Mysql 各种hash join算法讲解 hash join的概述 提到hash join之前自然得说Nest loop join,以两个表的关联为例,它其实是个双层循环,先遍历外层的表(n条),再 ...
- MySQL 优化器原来是这样工作的
文章目录 优化器概述 逻辑转换 基于成本的优化 控制优化程度 设置成本常量 数据字典与统计信息 控制优化行为 优化器和索引提示 总结 大家好,我是只谈技术不剪发的 Tony 老师.我们在 MySQL ...
- mysql not in优化_98%的人不知道的MySQL优化器原理
| 作者 梁东阳,数据库研发中心数据库内核工程师,负责腾讯云MySQL的内核开发. 在日常运维中,相信不少人都收藏了很多关于查询优化的方法论和小技巧,但是仔细想想,你真的了解这些优化背后的原理吗? ...
- 起源自天文学的PostgreSQL 优化器成本因子校对
标签 PostgreSQL , 优化器 , 成本因子 , 校对 背景 最近在写一个PostgreSQL数据库培训PPT, 其中有explain的讲解需求, 刚刚接触PostgreSQL的童鞋对Post ...
- MySQL优化器选错索引情况
MySQL优化器选错索引情况 1. 优化器选错索引 2. 优化器的逻辑 3. 索引选择异常和处理 1. 优化器选错索引 之前MySQL架构以及执行sql查询语句介绍过MySQL优化器可以帮助我们优化s ...
- mysql优化器怎么选择索引,为什么MySQL查询优化器会选择聚集主索引上的二级索引?...
为什么Mysql优化器在执行'select * from lookup'而没有order by子句时选择二级索引. 它只是一个侥幸,或者这是一个幕后优化,假设你添加了一个二级索引,它比主键更重要. 我 ...
- mysql优化器放弃索引场景,MYSQL索引优化(索引失效场景)
学习mysql是作为一名Java工程师必不可少的事情,但是我们只认识mysql的增删查改建表等等的sql语句其实远远不够的,对于进阶mysql来说,索引是一个很重要的部分.下面我们就来说一下在mysq ...
最新文章
- Ubuntu终端远程工具
- 为什么DL模型能够正确分类?SCOUTER(ICCV21')从“正”“反”方面说服你。
- EOS (3)系统特点
- gcnew 与 new 的区别
- 零基础学Python(第二十章 异常处理try)
- PowerPC VxWorks BSP分析(2)--PowerPC汇编
- python 神经网络工具_神经网络15分钟入门!使用python从零开始写一个两层神经网络...
- eclipse maven项目 class类部署不到tomcat下_Springboot介绍以及用Eclipse搭建一个简单的Springboot项目教程
- 关联分析(三)--GSP算法
- Windows API数据类型表
- 高级操作系统——XV6内存管理
- matlab画图一片空白的问题
- matlab求导赋值,MATLAB 函数先求导再赋值
- 尚硅谷java——个人收支记录软件
- Python语言程序设计基础_实验3 流程控制I_答案_通识教育必修课程_上海师范大学
- 木马万能查杀清除方法,木马专杀
- BCIduino转载|3D打印机使用的日常问题汇总
- Vue3学习笔记:了解并使用Pinia状态管理
- 模拟CMOS集成电路设计入门学习(10)
- 怎样画流程图攻略:流程图绘制软件使用方法