好久沒寫筆記了,來記一次優化sql的過程。
需求
對一張數據量約200萬條的表進行單表查詢,需要對app_id這個字段去重,只保留每個app_id的最新一條記錄。
我的思路
因為數據庫里設置了ONLY_FULL_GROUP_BY,使得select的字段只能與group by的字段相同,或是使用聚合函數,所以不能直接用下面的sql:
select * from t group by app_id order by date DESC
且在這張表中,id越大數據越新,因此先在一個子查詢里用group by分組去重,取出每組的最大id,再用in判斷即可,sql大致如下。
select * from t where id in
(select max(id) from t group by app_id)
問題
執行后發現查詢時長11s,給app_id加上索引后縮短為4s。
4s的時長還是很影響使用體驗,需要繼續優化。
排查過程
首先思考的可能性是子查詢效率太低,或許是max()拖慢了速度,但單獨執行子查詢后發現時長僅為0.1s,再看了下整個sql的解釋信息:
問題源頭出來了,這200萬條數據居然沒有走索引!
然后又查了下資料,發現in不會走索引,它會老老實實掃全表。
於是這只能放棄in了呀。
解決方法
因為子查詢出來的數據量相對較小,只有300多條,因此將in替換為left join,原先子查詢的表作為主表。
SELECT t2.*
FROM (
SELECT max( id )
FROM t
GROUP BY t.app_id) t1
LEFT JOIN t t2 ON t1.id = t2.id
查詢時長約為0.2s,撒花~