记一次MySQL子查询in不走索引优化
2021-09-26 本文已影响0人
神易风
最近在项目里面将Druid的SQL监控打开,发现了一个慢SQL查询,单表查询数据只有几万条,执行数据居然要2s,SQL如下
SELECT * FROM
instance_metric
WHERE id in (select min(id) from instance_metric GROUP BY code )
explain分析SQL
看起来没什么问题,子查询过滤出重复记录,返回最小id ,in 后面接入的是id,数据很快才对的啊。使用explain 分析执行过程,结果大失所望
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | PRIMARY | instance_metric | NULL | ALL | NULL | NULL | NULL | NULL | 619621 | 100.00 | Using where |
2 | SUBQUERY | instance_metric | NULL | ALL | NULL | NULL | NULL | NULL | 619621 | 100.00 | Using temporary |
可以看出in 后面并没有走索引查询,走了全表扫描,很纳闷。
正常in接参数
直接使用id 放入in 括号中
EXPLAIN select * from instance_metric WHERE id in (1,2,3);
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | instance_metric | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 3 | 100.00 | Using where |
执行结果没问题的,查询是走索引的
使用表关联代替in
本来想着使用exists代替in 使用,发现exists好像写不出来,不知道怎么取到最大值、最小值比较。当没有办法时,冷静来想想使用id来过滤重复记录,为什么不使用表关联呢,我的是个天才啊😀。
EXPLAIN select i.* from instance_metric i inner JOIN (select min(id) id from instance_metric GROUP BY code ) t1 on t1.id = i.id
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 10 | 100.00 | Using where |
1 | PRIMARY | i | NULL | eq_ref | PRIMARY | PRIMARY | 4 | t1.id | 1 | 100.00 | NULL |
2 | DERIVED | instance_metric | NULL | ALL | NULL | NULL | NULL | NULL | 10 | 100.00 | Using temporary |
可以看到内表关联是走索引的,搞定。