最近在項目裏面將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 |
可以看到內表關聯是走索引的,搞定。