MySQL性能优化(七)优化or查询的另一个例子
优化or查询的另外一个例子。
一个例子
SELECT msg.msg_id, msg.content , … FROM msg LEFT JOIN user ON msg.user_id = user.user_id LEFT JOIN group ON msg.group_id = group.group_id WHERE msg.gmt_modified >= date_sub('2018-04-29 09:31:44', INTERVAL 30 SECOND) OR user.gmt_modified >= date_sub('2018-04-29 09:31:44', INTERVAL 30 SECOND) OR group.gmt_modified >= date_sub('2018-04-29 09:31:44', INTERVAL 30 SECOND)
业务上只需要查询最近半分钟内有变化的数据。但是由于SQL语句的where条件中,用到了3个表的gmt_modified字段来过滤数据,必须要先将3个表的所有数据都关联出来,然后才能过滤数据,导致查询性能较差。
我们将SQL拆分成3个部分:
SQL片段一
SELECT msg.msg_id, msg.content , … FROM msg LEFT JOIN user ON msg.user_id = user.user_id LEFT JOIN group ON msg.group_id = group.group_id WHERE msg.gmt_modified >= date_sub('2018-04-29 09:31:44', INTERVAL 30 SECOND)
这种情况下,以MSG表作为驱动表,可以先过滤出msg表gmt_modified在半分钟之内的数据,然后再去关联user和group表,大大减少了需要关联的数据。
SQL片段二
SELECT msg.msg_id, msg.content , … FROM msg LEFT JOIN user ON msg.user_id = user.user_id LEFT JOIN group ON msg.group_id = group.group_id WHERE user.gmt_modified >= date_sub('2018-04-29 09:31:44', INTERVAL 30 SECOND)
类似的,这里可以以user表为驱动表,先过滤user表的数据,再进行关联。
SQL片段三
SELECT msg.msg_id, msg.content , … FROM msg LEFT JOIN user ON msg.user_id = user.user_id LEFT JOIN group ON msg.group_id = group.group_id WHERE group.gmt_modified >= date_sub('2018-04-29 09:31:44', INTERVAL 30 SECOND)
group表的数据极少变动,所以这个SQL片段基本很少需要执行。
将SQL拆分成3个部分后,优化器可以对这3个SQL片段分别优化,选取不同的表关联顺序。
总结
SQL的写法灵活,表达能力强,但是在一些特定的场景下,我们需要将复杂SQL进行拆分,使优化器可以选择最优的执行计划。