Mysql多表连接order by优化场景

一天,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来解决,这里不赘述。

posted @   lhbili  阅读(80)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示