Using OR on WHERE statement in MySql causes slow excecution

依然范特西╮ 提交于 2020-01-11 12:09:26

问题


The following query takes mysql to execute almost 7 times longer than implementing the same using two separate queries, and avoiding OR on the WHERE statement. I prefer using a single query as I can sort and group everything.

Here is the problematic query:

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');

Result:

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

Now if I do the following two queries instead, the aggregate execution time, as said, is shorter by 7 times:

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');

Result:

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

and:

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');

Result:

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

Obviously the amount of scanned rows is much lower on the two queries. Why is the initial query slow? Thanks.


回答1:


Yes, OR is frequently a performance-killer. A common work-around is to do UNION. For your example:

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');

If you are sure there are not dups, change to the faster UNION ALL.

If you are not fishing for missing team_users rows, use JOIN instead of LEFT JOIN.

If you need ORDER BY, add some parens:

( SELECT ... )
UNION ...
( SELECT ... )
ORDER BY ...

Otherwise, the ORDER BY would apply only to the second SELECT. (If you also need 'pagination', see my blog .)

Please note that you might also need LIMIT in certain circumstances.




回答2:


The queries without the OR clause are both sargable. That is, they both can be satisfied using indexes.

The query with the OR would be sargable if the MySQL query planner contained logic to figure out it can rewrite it as the UNION ALL of two queries. By the MySQL query planner doesn't (yet) have that kind of logic.

So, it does table scans to get the result set. Those are often very slow.



来源:https://stackoverflow.com/questions/39973833/using-or-on-where-statement-in-mysql-causes-slow-excecution

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!