暂无图片
暂无图片
10
暂无图片
暂无图片
3
暂无图片

MySQL优化实战之优化器罢工

原创 aisql 2023-07-25
665
1、发现问题

昨天跟踪线上慢SQL,发现有一条SQL始终走全表扫描,造成查询非常慢,查询时间达到了10分钟。

2、问题复现

SQL语句非常长。估计有上百行。这里就不贴原语句了,通过分析,找到了根本原因,我这里利用MySQL demo库sakila来重现

有如下语句

explain SELECT COUNT(*) FROM PAYMENT where staff_id in(1,2) and rental_id in (41,42,43,44) and customer_id in(39,40,41,42,43,44,45,46);
复制

查看执行计划。走的是全表扫描。
L2PX4PI1OVAMRIMV2E7C.png

查看该表结构

show create table PAYMENT;
复制

0KLQ5IB0AFGFFAKK63.png
我where 条件的三个字段都有索引 ,为什么该语句会走全表扫描呢?

当时我在生产环境是百思不得其解。找了好久好久原因。这里就直接的揭晓原因

explain 后去执行show warining;

show warnings;
复制

_YTDYX5K2V3~54NWXAGJO.png

可以看到,除了改写的语句,还有一条警告,正是由于这个警告是造成全表扫描的根本原因。

生产环境是由于SQL太长,已超过了range_optimizer_max_mem_size默认值,在这里为了好重现。我改变了range_optimizer_max_mem_size的值

SET @@SESSION.range_optimizer_max_mem_size = 500;
复制

用SET_VAR Hint其实更好观察这个问题

explain SELECT /*+ SET_VAR(range_optimizer_max_mem_size = 500) */ COUNT(*) FROM PAYMENT where staff_id in(1,2) and rental_id in (41,42,43,44) and customer_id in(39,40,41,42,43,44,45,46);
复制

N2B`_N~OYNZ4OHBE33.png

当range_optimizer_max_mem_size = 500 时全表扫描

explain SELECT /*+ SET_VAR(range_optimizer_max_mem_size = 5000) */ COUNT(*) FROM PAYMENT where staff_id in(1,2) and rental_id in (41,42,43,44) and customer_id in(39,40,41,42,43,44,45,46);
复制

TXLQCACWMVUC8JJ24`0X.png
当range_optimizer_max_mem_size = 5000 时 正常走了索引

这里我发现一个官方文档的错误。官方文档指出 range_optimizer_max_mem_size 不支持 SET_VAR,但上面可以看出我实际操作是可以用SET_VAR的。
X5NBENWC8G3CXB~2YK.png

这里官方文档明显错了。各位大佬可自行尝试。我测试的版本为 8.0.32

具体range_optimizer_max_mem_size 变量相关与范围优化说明可参见文末官方文档链接。

参考:
mysql系统变量
mysql范围优化

最后修改时间:2023-07-26 09:55:12
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论

暂无图片
1年前
评论
暂无图片 0
其中范围访问方法有一个候选关键字, 每个与OR组合的谓词使用大约230个字节 每个与AND组合的谓词使用大约125个字节 in()列表中的每个文字值都算作与OR组合的谓词。如果有两个IN()列表,则与OR组合的谓词数量是每个列表中文字值数量的乘积。因此,在前面的情况下,与OR组合的谓词的数量是M×N。 这算法真麻烦!
1年前
暂无图片 点赞
评论
暂无图片
1年前
评论
暂无图片 1
range_optimizer_max_mem_size 默认值是8K. 那怎么算一个SQL占用内存多少呢? 还是算SQL总长度? 会涉及字符集大小吗?
1年前
暂无图片 1
1
chengang
暂无图片
1年前
回复
暂无图片 0
文末的官方文档链接中,有计算长度方法。
1年前
暂无图片 点赞
回复