mysql优化

一个小小的改动,优化掉Using temporary; Using filesort

问题

项目开发过程中,发现某条sql出现了以下错误

1
Out of sort memory,  consider increasing server sort buffer size

错误原因是待排序的内容过大,导致 buffer 不够用

其实以前就出过一次问题,当时给排序的 create_time 字段加上索引就解决了

定位到问题sql如下

1
2
3
4
5
6
7
8
9
10
11
12

SELECT a.id
from a
LEFT JOIN ac on a.column_id = ac.id
LEFT JOIN ic ON a.ic_id = ic.id
where not exists(select 1 from gb where gb.type = 1 and gb.service_id = ac.id)
and a.`level` = 1
and a.state = 0
and ac.state = 1
order by a.create_time desc
limit 1, 15;

排查

首先对sql进行 explain,结果如下

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredextra
1SIMPLEacALLPRIMARY2510Using where; Using temporary; Using filesort
1SIMPLEgbrefgoods_bind_service_id_type_indexgoods_bind_service_id_type_index14zfapp_app.ac.id,const1100Using where; Not exists; Using index
1SIMPLEarefidx_columnidx_column8zfapp_app.ac.id3551Using where
1SIMPLEiceq_refPRIMARYPRIMARY8zfapp_app.a.ic_id1100

里面出现了非常可怕的 Using temporary; Using filesort

另外出现的顺序也有点奇怪,我是以a表为主表,但是出现在第一项的是ac

解决

在一点点的测试之后,终于找到了问题所在。

where之后的 and ac.state = 1 移到 join后面,最终sql如下

1
2
3
4
5
6
7
8
9
10

SELECT a.id
from a
LEFT JOIN ac on a.column_id = ac.id and ac.state = 1
LEFT JOIN ic ON a.ic_id = ic.id
where not exists(select 1 from gb where gb.type = 1 and gb.service_id = ac.id)
and a.`level` = 1
and a.state = 0
order by a.create_time desc
limit 1| 15;

再 explain一下

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredextra
1SIMPLEarefindexidx_create_time8121Using where; Backward index scan
1SIMPLEiceq_refPRIMARYPRIMARY8zfapp_app.a.ic_id1100
1SIMPLEaceq_refPRIMARY8zfapp_app.a.column_id2510Using where
1SIMPLEgbrefgoods_bind_service_id_type_indexgoods_bind_service_id_type_index14zfapp_app.ac.id,const1100Using where; Not exists; Using index

结果正常了

原理

先随便猜测一下,对表的判断写在join里面,就只是对该表做回表,写在外面就是将两个表合并排序,问题很大


mysql优化
http://blog.inkroom.cn/2022/06/21/F3R2NS.html
作者
inkbox
发布于
2022年6月21日
许可协议