一次线上故障“MySQL 选错索引”实录

刚到家,收到 1 条阿里云报警短信提示云数据库 RDS 内存占用超过阈值,于是去阿里云控制台查看

SQL 慢日志,发现一条 SQL 语句在 20:30 左右执行过 4 次且每次扫描行 8kw 条记录,单次耗时 500 多秒:


SQL模板如下:

1
2
3
4
5
6
7
8
9
10
11
SELECT material_id, create_time, update_late_time, create_user_id, team_id
, api_access_id, width, height, content_type, attach_id
, file_key, md5, file_size, folder_id, is_person
, is_del, is_open, copyright_user_id, title, keywords
, review_status, is_selected, is_hide, file_name
FROM material_fixed_part
WHERE create_user_id = ?
AND team_id = ?
AND is_del = ?
ORDER BY material_id DESC
LIMIT ?, ?

很吃惊,因为这不是近期新上线的新功能,而且其 SQL 之前我也有给加过索引,便准备了两个 Demo 进行测试,发现仅仅是 create_user_id 取值的不同,但实际上却用了不同的索引:


create_user_id 取值 9505927 的 SQL 语句使用了 uk_materialid 索引,material_id 是表的唯一索引,而且该字段为 bigint 类型,且记录分布的也及其不均衡,不慢才怪!

与阿里的工程师交流,让把语句中 ORDER BY material_id DESC 改为 ORDER BY material_id+0 DESC,我这边是拒绝的,这样改我们的开发工程师理解起来比较费力,我在想能否给语句指定其使用的索引,查了下资料,FORCE INDEX 即可实现,则改写 SQL 语句为:

1
2
3
4
5
6
7
8
9
10
11
12
SELECT material_id, create_time, update_late_time, create_user_id, team_id
, api_access_id, width, height, content_type, attach_id
, file_key, md5, file_size, folder_id, is_person
, is_del, is_open, copyright_user_id, title, keywords
, review_status, is_selected, is_hide, file_name
FROM material_fixed_part
FORCE INDEX(idx_createuserid_folderid_isdel)
WHERE create_user_id = ?
AND team_id = ?
AND is_del = ?
ORDER BY material_id DESC
LIMIT ?, ?

解决问题要紧,至于 MySql 为什么会选错索引以及还有没有别的解决方案,就留待日后再去探索吧!


一次线上故障“MySQL 选错索引”实录
https://blog.yohlj.cn/posts/f0b4283b/
作者
Enoch
发布于
2020年1月14日
许可协议