连接查询成本(2)---mysql进阶(四十二)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 连接查询成本(2)---mysql进阶(四十二)

前面说了mysql每次索引优化是有成本的,先看全表扫描成本,在看索引扫描成本,最后选出最小成本,每次访问页的成本量大概是1,读取和效验数据是否符合条件,成本大概是0.2,读取和效验数据和文件排序等称为CPU成本,查询页等称为I/O成本。可以用show index from tb,来看表都有什么数据,其中cardinality表示重复率,比较重要

mysql基于成本的优化(1)---mysql进阶(四十一)


连接查询成本


为了连接表,我们在创建一个和single_table一样的表,single_table2,简称s2。

Condition filtering介绍

我们前面说过连接查询主要要查驱动表和被驱动表,被驱动表的查询次数,取决于驱动表查询出来的数据行数,所以成本为:


多次查询被驱动表成本


我们把驱动表查询出来的数据称为驱动表的扇出(fanout),显然扇出越小,被驱动查询次数越少,成本越低,所以成本可以看这个扇出值:

SELECT * FROM single_table AS s1 INNER JOIN single_table2 AS s2;

显然这是驱动表全表查询,我们前面统计了s1的数据9693行,所以扇出值为9693。

SELECT * FROM single_table AS s1 INNER JOIN single_table2 AS s
WHERE s1.key2 >10 AND s1.key2 < 1000;

此处很显然用key2唯一二级索引查询,我们前面计算了此区间的值由95条数据,所以扇出值是95。

但下面的sql就比较麻烦:

SELECT * FROM single_table AS s1 INNER JOIN single_table2 AS s2
   WHERE s1.common_field > 'xyz';

这里因为加了个非索引过滤值,查询优化器又不会真的去查询,只会猜9693有多少条数满足。

SELECT * FROM single_table AS s1 INNER JOIN single_table2 AS s2
   WHERE s1.key2 > 10 AND s1.key2 < 1000 AND
         s1.common_field > 'xyz';

这里就是在前面的区间95条的基础上,再猜多少符合非索引过滤的条件。

说了这么多,其实就是表达很多情况下,驱动表的扇值需要猜:

使用全部查询,计算扇出满足过滤条件时。

使用索引执行单表查询,那么需要把其他过滤条件计算满足多少。

Mysql吧这种猜的过程就叫做condition filter。


两个表连接的成本分析


连接查询的计算公式,总成本 = 单词访问驱动表成本 + 驱动表扇出 + 单次访问被驱动表成本。

对于左连接和右连接,驱动表是固定的,只要分别为驱动表和被驱动表找到最优的解决方法。

可对于内连接,驱动表和被驱动表是可以互换的,所以考虑两个方面,不同表作为驱动表成本不同,取最优

SELECT * FROM single_table AS s1 INNER JOIN single_table2 AS s2
   ON s1.key1 = s2.common_field
   WHERE s1.key2 > 10 AND s1.key2 < 1000 AND
         s2.key2 > 1000 AND s2.key2 < 2000;

很显然,内连接更麻烦一些,上面是一个内连接sql,

以s1为驱动表的话:

先用唯一索引确定驱动表的扇值,就是s1.key2>10 and s1.key2<1000的扇值。然后查询s2的条件就是 s.common_field = 值 和>1000 and <2000的两个条件,这时候可以选择全表查询或者索引查询+回表,我们假设索引成本更低。

这时候就是s1表key2的成本 + s1的扇出 * 使用s2.key2的访问成本

以s2为驱动表的话:

先用唯一所以s2.key2确定扇出,然后根据扇出值,查询s1的条件就是s1.key1 = 值 和 > 10 and <1000,这里第一个是ref访问,第二个是range访问,一般来说ref会快很多,所以我们这里默认采用第一个。

这时候成本 = s2表key2的成本 + s2的扇出 * 使用s1.key1的ref访问成本

从上面可以看出,成本主要来自扇出 个 被驱动表的访问成本,所以优化器会选择扇出更小和被驱动表访问成本更低的来查询。


多表连接成本分析


对于两个表连接,连接顺序:2*1 = 2

对于三个表连接,连接顺序:3*2*1 = 6

对于四个表连接,连接顺序:4*3*2*1=24

这种n的阶层连接顺序也就是叫n!

那么每次都全部分析一遍不是很耗费成本吗?mysql有几种解决办法:

提前结束计算:比如ABC三个表连接,维护一个全局最低成本变量,当ABC成本已经最低时候,bc计算的成本大于最低成本就直接取消,不计算bcd了。

系统变量optimizer_search_depth:mysql设置了当前变量,若越大,成本分析越精确,越有好的执行结果,但耗时,否则得不到好的执行结果,但很节约时间。

启发式规则:mysql有启发式规则和系统变量,凡事不满足这些规则的,直接不分析,这样也导致会错失最优执行计划。

调节成本常数

我们前面介绍了两个成本常量,一个是刷新页为1.0,一个是cpu排序或者读取效验数据是0.2,我们可以从数据库看到这两张表。

mysql> SHOW TABLES FROM mysql LIKE '%cost%';
+--------------------------+
| Tables_in_mysql (%cost%) |
+--------------------------+
| engine_cost              |
| server_cost              |
+--------------------------+
2 rows in set (0.00 sec)

我们在第一章说过,一条语句执行分为server和存储引擎。

Server管理:连接管理,查询缓存,语法解析,sql优化等,这里是没有涉及到数据的,也就是和操作引擎没有关系,所以这些操作的成本常量都在server.cost表里。

mysql> SELECT * FROM mysql.server_cost;
+------------------------------+------------+---------------------+---------+
| cost_name                    | cost_value | last_update         | comment |
+------------------------------+------------+---------------------+---------+
| disk_temptable_create_cost   |       NULL | 2021-03-14 10:20:20 | NULL    |
| disk_temptable_row_cost      |       NULL | 2021-03-14 10:20:20 | NULL    |
| key_compare_cost             |       NULL | 2021-03-14 10:20:20 | NULL    |
| memory_temptable_create_cost |       NULL | 2021-03-14 10:20:20 | NULL    |
| memory_temptable_row_cost    |       NULL | 2021-03-14 10:20:20 | NULL    |
| row_evaluate_cost            |       NULL | 2021-03-14 10:20:20 | NULL    |
+------------------------------+------------+---------------------+---------+
6 rows in set (0.02 sec)

Cost_name:名称。

Cost_Value:对应的值,null表示默认值。

后面两个表示最后更新时间和注释。

Dis_temptable_create_cost:默认值40.0,创建磁盘临时表成本,增大这个值,会让磁盘尽量少的创建临时表

Dis_temptable_row_cost:默认值1.0,向磁盘写入或者读取一条数据,增大这个值,会让磁盘尽量少的创建临时表。

Key_compare_cost:默认值0.1,两条记录作比较,多用在操作顺序上,增大这个值会提升filesort成本,让优化器更倾向使用索引排序而不是filesort。

Memory_temptable_create_cost:默认值2.0,创建基于内存的临时表成本,如果增大,优化器会尽力创建少的内存临时表。

Memory_temptable_row_cost:默认值0.2,向内存写入或者读取一条数据,如果增大,优化器会尽力创建少的内存临时表。

Row_evaluate_cos:默认值0.2,这是一直用于检测一条记录是否符合搜索条件成本,若增大,会倾向全盘扫描

注意:mysql在执行distinct查询,分组查询,union等特殊查询时候,会在内部创建临时表,比如distinct查询会先在内部建一个unique索引的临时表,吧结果集放入这个表中,临时表在内存创建还是在磁盘创建,取决于数据量的大小,太大就只能在磁盘上创建。

如果想修改他当然是可以修改的,但修改完之后需要执行刷新语句:

UPDATE mysql.server_cost
   SET cost_value = 0.4
   WHERE cost_name = 'row_evaluate_cost';
//刷新语句
FLUSH OPTIMIZER_COSTS;

当然若想改回默认值,直接set null就好,然后执行flush optimizer_costs。

engine_cost表如下:

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-03-14 10:20:20 | NULL    |
| default     |           0 | memory_block_read_cost |       NULL | 2021-03-14 10:20:20 | NULL    |
+-------------+-------------+------------------------+------------+---------------------+---------+
2 rows in set (0.01 sec)

与前面相比,这里多了两列:

engine_name:指使用搜素引擎的名字,default默认全部适用

device_type:指使用的设备,固态硬盘还是机械硬盘0表示默认。

Io_block_read_cost:默认值1.0,从磁盘上读取一块对应的成本。在innodb引擎块就是页的概念,不过对于mySIMA来说,4096为一块。增大这个会加重I/O成本,让优化器倾向索引查询而不是全表查询。

Memory_block_Read_cost:默认值1.0,从内存读取一块的成本。

这里为什么内存和磁盘读取是一样的成本呢,因为mysql不能区分当前数据到底在内存还是在磁盘。。0.0

同理也可以更改这些数据。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
缓存 关系型数据库 MySQL
MySQL索引策略与查询性能调优实战
在实际应用中,需要根据具体的业务需求和查询模式,综合运用索引策略和查询性能调优方法,不断地测试和优化,以提高MySQL数据库的查询性能。
|
3天前
|
SQL 关系型数据库 MySQL
MySQL 窗口函数详解:分析性查询的强大工具
MySQL 窗口函数从 8.0 版本开始支持,提供了一种灵活的方式处理 SQL 查询中的数据。无需分组即可对行集进行分析,常用于计算排名、累计和、移动平均值等。基本语法包括 `function_name([arguments]) OVER ([PARTITION BY columns] [ORDER BY columns] [frame_clause])`,常见函数有 `ROW_NUMBER()`, `RANK()`, `DENSE_RANK()`, `SUM()`, `AVG()` 等。窗口框架定义了计算聚合值时应包含的行。适用于复杂数据操作和分析报告。
37 11
|
7天前
|
存储 关系型数据库 MySQL
mysql怎么查询longblob类型数据的大小
通过本文的介绍,希望您能深入理解如何查询MySQL中 `LONG BLOB`类型数据的大小,并结合优化技术提升查询性能,以满足实际业务需求。
36 6
|
21天前
|
关系型数据库 MySQL 网络安全
DBeaver连接MySQL提示Access denied for user ‘‘@‘ip‘ (using password: YES)
“Access denied for user ''@'ip' (using password: YES)”错误通常与MySQL用户权限配置或网络设置有关。通过检查并正确配置用户名和密码、用户权限、MySQL配置文件及防火墙设置,可以有效解决此问题。希望本文能帮助您成功连接MySQL数据库。
34 4
|
1月前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
60 9
|
1月前
|
安全 关系型数据库 MySQL
【赵渝强老师】MySQL的连接方式
本文介绍了MySQL数据库服务器启动后的三种连接方式:本地连接、远程连接和安全连接。详细步骤包括使用root用户登录、修改密码、创建新用户、授权及配置SSL等。并附有视频讲解,帮助读者更好地理解和操作。
116 1
|
1月前
|
缓存 监控 关系型数据库
如何优化MySQL查询速度?
如何优化MySQL查询速度?【10月更文挑战第31天】
80 3
|
1月前
|
SQL NoSQL 关系型数据库
2024Mysql And Redis基础与进阶操作系列(5)作者——LJS[含MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页等详解步骤及常见报错问题所对应的解决方法]
MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页、INSERT INTO SELECT / FROM查询结合精例等详解步骤及常见报错问题所对应的解决方法
|
1月前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
237 1
|
1月前
|
SQL 关系型数据库 MySQL
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
47 1
下一篇
DataWorks