💡 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;
|
运行结果:
2.分析问题
首先确认了表的数据量:
1
|
select COUNT(*) FROM store_evaluate
|
最终得出来该表的数据量大概是:20W 左右
尽管数据量并不小,但是也跟这个运行时间远远不能匹配;这么简单表结构,千万级别的数据量也不至于这个查询速度;
为了找到问题,不妨 Explain 看一下:

虽然看到的 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 = ?
|