MySQL调优学习笔记(四):MySQL优化器(CBO)

2023-10-07 16:40

本文主要是介绍MySQL调优学习笔记(四):MySQL优化器(CBO),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

MySQL优化器(CBO)

mysql索引一般建立在高选择性字段上,也有例外

总结

参考资料:姜承尧的MySQL实战宝典

MySQL优化器(CBO)

MySQL优化器决定了具体某一索引的选择,也就是常说的执行计划。优化器的选择是基于成本,它会分析所有可能的执行计划,哪个索引的成本越低,优先使用哪个索引。这种优化器称之为:CBO(Cost-based Optimizer,基于成本的优化器)。
MySQL 数据库由 Server 层和 Engine 层组成。Server 层有 SQL 分析器、SQL优化器、SQL 执行器,用于负责 SQL 语句的具体执行过程;Engine 层负责存储具体的数据,如最常使用的 InnoDB 存储引擎,还有用于在内存中存储临时结果集的 TempTable 存储引擎。

 在 MySQL中,一条 SQL 的计算成本公式如下:

Cost  = Server Cost + Engine Cost  = CPU Cost + IO Cost

其中,CPU Cost 表示计算的开销,比如索引键值的比较、记录值的比较、结果集的排序……;IO Cost 表示引擎层 IO 的开销,包括读取内存 IO 开销以及读取磁盘 IO 开销。

数据库 mysql 下的表 server_cost、engine_cost 记录了对于各种成本的计算。

SELECT * FROM mysql.server_cost;

表 server_cost 记录了 Server 层优化器各种操作的成本,这里面包括了所有 CPU Cost,具体含义如下。

  • disk_temptable_create_cost:创建磁盘临时表的成本,默认为20。
  • disk_temptable_row_cost:磁盘临时表中每条记录的成本,默认为0.5。
  • memory_temptable_create_cost:创建内存临时表的成本:默认为1。
  • memory_temptable_row_cost:内存临时表中每条记录的成本,默认为0.1。
  • key_compare_cost:索引键值比较的成本,默认为0.05。
  • row_evaluate_cost:记录间的比较成本,默认为0.1。

可以看到, MySQL 优化器认为如果一条 SQL 需要创建基于磁盘的临时表,则这时的成本是最大的,其成本是创建基于内存临时表的 20 倍。而索引键值的比较、记录之间的比较,其实开销是非常低的,但如果要比较的记录数非常多,则成本会变得非常大。

SELECT * FROM mysql.engine_cost;

而表 engine_cost 记录了 Engine 层各种操作的成本,这里包含了所有的 IO Cost,具体含义如下。

  • io_block_read_cost:从磁盘读取一个页的成本,默认值为1。
  • memory_block_read_cost:从内存读取一个页的成本,默认值为0.25。

也就是说, MySQL 优化器认为从磁盘读取的开销是内存开销的 4 倍。

不过,上述所有的成本都是可以修改的,比如如果数据库使用是传统的 HDD 盘,性能较差,其随机读取性能要比内存读取慢 50 倍,那可以通过下面的 SQL 修改成本:

INSERT INTO 
mysql.engine_cost(engine_name,device_type,cost_name,cost_value,last_update,comment) 
VALUES ('InnoDB',0,'io_block_read_cost',12.5,CURRENT_TIMESTAMP,'Using HDD for InnoDB');
FLUSH OPTIMIZER_COSTS;

mysql索引一般建立在高选择性字段上,也有例外

B+ 树索引通常要建立在高选择性的字段或字段组合上,如订单 ID、日期等,因为这样每个字段值大多并不相同。但在有些低选择性的列上,也是有必要创建索引的。

比如电商的核心业务表 orders,其有字段orderstatus,表示当前的状态。状态是有限的,一般仅为已完成、支付中、超时已关闭这几种。在电商业务中会有一个这样的逻辑:即会定期扫描字段 orderstatus 为支付中的订单,然后强制让其关闭,从而释放库存,给其他有需求的买家进行购买。通常订单状态绝大部分都是已完成,只有绝少部分会是支付中,因此订单状态是存在数据倾斜的。

虽然orderstatus是低选择性的,但是由于其有数据倾斜,且我们只是从索引查询少量数据,因此可以对orderstatus创建索引,根据索引查询的效率会更高。但优化器会认为数据是比较均匀的,为了避免通过二级索引再回表,使用全表扫描的效率会更高。这种情况下,我们可以利用 MySQL 8.0 的直方图功能,创建一个直方图,让优化器知道数据的分布,从而更好地选择执行计划。此时再去查询支付中的订单时,就会使用到索引了。

直方图的创建命令如下所示:

ANALYZE TABLE orders UPDATE HISTOGRAM ON orderstatus;

在创建完直方图后,MySQL会收集到字段 orderstatus 的数值分布,可以通过下面的命令查询得到:

SELECT * FROM information_schema.column_statistics
WHERE column_name = 'orderstatus';

总结

  • MySQL 优化器是 CBO 的,MySQL 会选择成本最低的执行计划;
  • 一般只对高选择性的字段和字段组合创建索引;
  • 当低选择性的字段数据存在倾斜,通过索引找出少部分数据,可以考虑创建索引。若数据存在倾斜,可以创建直方图,让优化器知道索引中数据的分布,进一步校准执行计划。

这篇关于MySQL调优学习笔记(四):MySQL优化器(CBO)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/159043

相关文章

MySQL 分区与分库分表策略应用小结

《MySQL分区与分库分表策略应用小结》在大数据量、复杂查询和高并发的应用场景下,单一数据库往往难以满足性能和扩展性的要求,本文将详细介绍这两种策略的基本概念、实现方法及优缺点,并通过实际案例展示如... 目录mysql 分区与分库分表策略1. 数据库水平拆分的背景2. MySQL 分区策略2.1 分区概念

MySQL高级查询之JOIN、子查询、窗口函数实际案例

《MySQL高级查询之JOIN、子查询、窗口函数实际案例》:本文主要介绍MySQL高级查询之JOIN、子查询、窗口函数实际案例的相关资料,JOIN用于多表关联查询,子查询用于数据筛选和过滤,窗口函... 目录前言1. JOIN(连接查询)1.1 内连接(INNER JOIN)1.2 左连接(LEFT JOI

MySQL 中查询 VARCHAR 类型 JSON 数据的问题记录

《MySQL中查询VARCHAR类型JSON数据的问题记录》在数据库设计中,有时我们会将JSON数据存储在VARCHAR或TEXT类型字段中,本文将详细介绍如何在MySQL中有效查询存储为V... 目录一、问题背景二、mysql jsON 函数2.1 常用 JSON 函数三、查询示例3.1 基本查询3.2

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL

MySQL中FIND_IN_SET函数与INSTR函数用法解析

《MySQL中FIND_IN_SET函数与INSTR函数用法解析》:本文主要介绍MySQL中FIND_IN_SET函数与INSTR函数用法解析,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一... 目录一、功能定义与语法1、FIND_IN_SET函数2、INSTR函数二、本质区别对比三、实际场景案例分

MySQL中的交叉连接、自然连接和内连接查询详解

《MySQL中的交叉连接、自然连接和内连接查询详解》:本文主要介绍MySQL中的交叉连接、自然连接和内连接查询,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、引入二、交php叉连接(cross join)三、自然连接(naturalandroid join)四

Mysql如何将数据按照年月分组的统计

《Mysql如何将数据按照年月分组的统计》:本文主要介绍Mysql如何将数据按照年月分组的统计方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql将数据按照年月分组的统计要的效果方案总结Mysql将数据按照年月分组的统计要的效果方案① 使用 DA

Mysql表如何按照日期字段的年月分区

《Mysql表如何按照日期字段的年月分区》:本文主要介绍Mysql表如何按照日期字段的年月分区的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、创键表时直接设置分区二、已有表分区1、分区的前置条件2、分区操作三、验证四、注意总结一、创键表时直接设置分区

mysql的基础语句和外键查询及其语句详解(推荐)

《mysql的基础语句和外键查询及其语句详解(推荐)》:本文主要介绍mysql的基础语句和外键查询及其语句详解(推荐),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录一、mysql 基础语句1. 数据库操作 创建数据库2. 表操作 创建表3. CRUD 操作二、外键

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析