从一个实例分析order by 优化

环境:

MySQL5.7.30

简介:

生产环境一张读压力很大的表,表数据量在3000万左右,该表主要是一条很简单的sql在查,因时入慢日志时间为1s,初期该sql并未进入到慢日志,一次引流导致出现了大量sql未走索引,活跃会话数激增,CPU瞬间打满的情况,由此引发了对优化器在索引选择上的一些思考。

建表语句如下:

因为生产环境,所以这里匿去表名,只分析原因,部分地方用test1代替:

CREATE TABLE `test1` (

`id` bigint(20) NOT NULL AUTO_INCREMENT,

`relation_code` varchar(64) DEFAULT NULL,

`left_user_id` bigint(20) DEFAULT NULL,

`right_user_id` bigint(20) DEFAULT NULL,

`top_level` tinyint(4) NOT NULL ,

`relation_type` tinyint(4) NOT NULL DEFAULT '1' ,

`update_time` timestamp NULL DEFAULT NULL,

PRIMARY KEY (`id`),

UNIQUE KEY `uni_relation_code` (`relation_code`),

KEY `idx_left_user_id` (`left_user_id`),

KEY `idx_right_user_id` (`right_user_id`),

KEY `idx_toplevel_leftuserid_rightuserid` (`top_level`,`left_user_id`,`right_user_id`)

) ENGINE=InnoDB ;

查询接口对应的sql:

SELECT `top_level`

FROM `test1`

WHERE left_user_id = ?

OR right_user_id = ?

ORDER BY `top_level` DESC

LIMIT ? 

从表结构可以看出,该sql就是一条很简单的常量 + order by ,对应可用的索引可以用:

1. index_merge(idx_left_user_id,idx_right_user_id)

但使用该方式在合并了索引过滤出来的数据后,会产生一次file sort,进行一次回表操作

2. idx_toplevel_leftuserid_rightuserid

该索引为一条覆盖索引,从order by 的字段上开始过滤符合条件的数据,达到limit的条数后直接返回结果,从分析上看,所有操作在索引中就可以完成,不需要回表操作,似乎比较符合。

从explain的结果来看:

 实际上优化器选择的是index_merge。

先看一下使用两条索引时对应的查询耗时:

1. 使用 index_merge 时:

 2. 使用 idx_toplevel_leftuserid_rightuserid 时:

可以看到,使用覆盖索引比使用index_merge快10倍以上,至于优化器为什么选择的是index_merge,而不是覆盖索引,下一篇文章咱们再分析,这里先分析为什么引流的时候会导致部分查询走全表扫描,导致数据库异常。

分析问题:

order by/ group by {字段} + limit {条数} 这类的查询优化器会走 {字段} 为前缀的索引,然后扫描where条件的行,凑足limit的行数后直接返回,不再继续往下扫描,所以这里优化器理论上应该选择覆盖索引(idx_toplevel_leftuserid_rightuserid),实际上从执行耗时来看,也确实是这样,但实际上该查询方式会导致查询效率不稳定,可能导致有的sql执行很快,有的sql执行很慢,甚至是全表扫描的情况发生。

解决方式:

使用hint,加上强制索引 idx_toplevel_leftuserid_rightuserid 可以避免全表扫描的情况发生。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FightingFreedom

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值