在MySql中使用OR对WHERE语句导致缓慢执行

时间:2016-10-11 09:05:38

标签: mysql query-optimization

以下查询使mysql的执行时间比使用两个单独的查询实现相同的时间长7倍,并且在WHERE语句中避免使用OR。我更喜欢使用单个查询,因为我可以对所有内容进行排序和分组。

以下是有问题的查询:

EXPLAIN SELECT  *
    FROM  `posts`
    LEFT JOIN  `teams_users`
               ON (teams_users.team_id=posts.team_id
              AND  teams_users.user_id='7135')
    WHERE  (teams_users.status='1'
              OR  posts.user_id='7135');

结果:

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE  posts       ALL    user_id NULL NULL NULL 169642 
1 SIMPLE  teams_users eq_ref PRIMARY PRIMARY 8 posts.team_id,const 1 Using where

现在,如果我执行以下两个查询,那么聚合执行时间会缩短7倍:

EXPLAIN SELECT  *
    FROM  `posts`
    LEFT JOIN  `teams_users`
               ON (teams_users.team_id=posts.team_id
              AND  teams_users.user_id='7135')
    WHERE  (teams_users.status='1');

结果:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE  teams_users ref PRIMARY,status status 1 const 5822 Using where
1 SIMPLE  posts       ref team_id  team_id 5 teams_users.team_id 9 Using where

EXPLAIN SELECT  *
    FROM  `posts`
    LEFT JOIN  `teams_users`
               ON (teams_users.team_id=posts.team_id
              AND  teams_users.user_id='7135')
    WHERE  (posts.user_id='7135');

结果:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE  posts       ref    user_id user_id 4 const 142 
1 SIMPLE  teams_users eq_ref PRIMARY PRIMARY 8 posts.team_id,const 1

显然,两个查询的扫描行数量要少得多。 为什么初始查询速度慢? 感谢。

2 个答案:

答案 0 :(得分:0)

是的,from os import startfile; proj = QgsProject.instance(); UriFile = unicode(proj.fileName()); img = '[% "pad" %]'; Path = unicode(os.path.dirname(UriFile)); startfile(Path+img) from os import startfile; proj = QgsProject.instance(); UriFile = unicode(proj.fileName()); img = '[% "pad" %]'; Path = unicode(os.path.dirname(UriFile)); startfile(Path+img) 经常是性能杀手。常见的解决方法是OR。以你的例子:

UNION

如果您确定没有重复,请更改为更快SELECT * FROM `posts` LEFT JOIN `teams_users` ON (teams_users.team_id=posts.team_id AND teams_users.user_id='7135') WHERE (teams_users.status='1') UNION DISTINCT SELECT * FROM `posts` LEFT JOIN `teams_users` ON (teams_users.team_id=posts.team_id AND teams_users.user_id='7135') WHERE (posts.user_id='7135');

如果您没有捕获丢失的UNION ALL行,请使用team_users代替JOIN

如果您需要LEFT JOIN,请添加一些内容:

ORDER BY

否则,( SELECT ... ) UNION ... ( SELECT ... ) ORDER BY ... 仅适用于第二个ORDER BY。 (如果您还需要'分页',请参阅my blog。)

请注意,在某些情况下,您可能还需要SELECT

答案 1 :(得分:0)

没有OR子句的查询都是sargable. That is, they both can be satisfied using indexes

如果MySQL查询规划器包含逻辑以确定它可以将其重写为两个查询的OR,则UNION ALL的查询将是可搜索的。通过MySQL查询计划器还没有(还)具有那种逻辑。

因此,它会进行表扫描以获取结果集。那些往往很慢。