刚到家,收到 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_nameFROM material_fixed_partWHERE 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_nameFROM 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 为什么会选错索引以及还有没有别的解决方案,就留待日后再去探索吧!