【Mysql】order by + Limit 导致慢查询

💡 Tips:腾讯云的mysql服务存在的一些慢SQL,进行优化记录: 📢 因为不当的使用 order by + limit 导致的慢查询的记录

1.描述

表结构:

1
2
3
4
5
6
7
8
9
CREATE TABLE `store_evaluate` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `star_cont` text COMMENT '评分内容,json',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  `deleted_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_0` (`deleted_at`,`created_at`)
) ENGINE=InnoDB AUTO_INCREMENT=169949 DEFAULT CHARSET=utf8 ;

执行语句:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
SELECT
  *
FROM
  `store_evaluate`
WHERE
    (
      `created_at` >= '2023-09'
      AND `created_at` < '2023-10'
    )
  AND `store_evaluate`.`deleted_at` IS NULL
ORDER BY
  `id` DESC
LIMIT
  1;
	

运行结果:
image.png

2.分析问题

首先确认了表的数据量:

1
select COUNT(*) FROM store_evaluate

最终得出来该表的数据量大概是:20W 左右
尽管数据量并不小,但是也跟这个运行时间远远不能匹配;这么简单表结构,千万级别的数据量也不至于这个查询速度;

为了找到问题,不妨 Explain 看一下:
image.png
虽然看到的 rows:2; 看上去好像很小,但是如果细细思考还是存在问题的:
如果执行
sql
中,优化器为我们选取了 ID 主键索引作为索引去执行这个语句的话,其实是没有办法达到他预期的 rows 的效果的;因为 where 语句执行最优解应该使用 index_0 索引才是最有解;
既然有了问题猜想,就可以朝着这个方向优化;

3.解决方法

3.1 方案一:手动调整合适索引

Sql 增加建议索引。一般情况下,加了建议索引,mysql 就会走建议的索引,而不是自己去选择。

1
select [data] from [table] use index(idx) where [condition] order by [sort] limit ?

② 当然也可以强制 Sql 走建议的所以

1
select [data] from [table] force index(idx) where [condition] order by [sort] limit ?

③ 当然我们也能禁用当前语句比较慢的索引:

1
select [data] from [table] ignore index(idx) where [condition] order by [sort] limit ?

这里我们选择禁用而不是直接去删除慢索引:

  • 这个语句中的索引比较慢不代表其他语句中会慢
  • 大表索引的修改DDL,会导致锁表,从而线上服务暂停;
  • 大表DDL 语句时间一般非常久

3.2 方案二:不使用 order + limit

我们不难发现:上面的语句通过 **order by + limit 1 **目的是为了获取范围内最后一条;
同理可得:

1
2
3
4
5
select max(id) from [table] where [condition]

+

select * from [table] where id = ?
0%