一天,DBA突然发来一条慢SQL告警, SQL如下:
SELECT s.msg, t.msg, o.msg, GROUP_CONCAT(t.tId) AS tIdList FROM t_o o LEFT JOIN t_s s ON o.id= s.oId LEFT JOIN t_t t ON t.oId= o.id WHERE o.type = 'B' AND o.status = 'HAS_PAY' AND t.type = '2002' AND o.time <= '2023-11-11 15:46:41.0' AND o.time>= '2023-11-04 15:46:41.0' GROUP BY o.id ORDER BY o.id DESC
经验老练的导师(瞧了瞧我这条SQL):你把order by o.id 换成 t.oId 或者 s.oId试试看
我:啊,这有什么不一样的吗?
经验老练的导师(不屑的表情):你试试就晓得了咯
我把SQL调整如下:
SELECT s.msg, t.msg, o.msg, GROUP_CONCAT(t.tId) AS tIdList FROM t_o o LEFT JOIN t_s s ON o.id= s.oId LEFT JOIN t_t t ON t.oId= o.id WHERE o.type = 'B' AND o.status = 'HAS_PAY' AND t.type = '2002' AND o.time <= '2023-11-11 15:46:41.0' AND o.time>= '2023-11-04 15:46:41.0' GROUP BY t.oId ORDER BY t.oId DESC
一运行发现SQL的查询时间变成了100ms(原SQL是300多ms)
我:蛙趣,什么情况,佬,这是玄学嘛?
经验老练的导师(得意洋洋):因为你原SQL应该用连表后的临时表进行了排序,没有走索引,所以效率慢,你Explain一下就知道了
explain结果
- 优化前的SQL:Using index condition; Using temporary; Using filesort
- 优化后的SQL:Using where
首先讨论一下Using filesort,我们知道Mysql是有两种排序的,index 和 filesort,如果order by的条件不在索引列上就会filesort
但是我们的o.id是主键呀,有索引的哦。
Using temporary,表示用到了临时表,Mysql连表的时候会分驱动表和非驱动表,驱动表默认是数据最小的表,另外的叫非驱动表
首先处理驱动表的数据,之后再和非驱动表进行连接匹配操作。因此对于驱动表的字段是可以直接排序的,而非驱动表的字段需要合并结果(临时表)进行排序,于是产生了filesort
到这里就可以解释上述现象了,并且上述SQL还可以用straight_join来解决,这里不赘述。
标签:多表,Mysql,oId,order,SQL,msg,Using,filesort,id From: https://www.cnblogs.com/lhbilibili/p/18184046