好久没写笔记了,来记一次优化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,撒花~