繁体   English   中英

在左联接的表上使用 WHERE OR 时查询速度很慢?

[英]Query is slow when use WHERE OR on tables left join?

我有表user关系 OneToMany 到表A和表B 我需要在表A和表B上找到其合作伙伴 = 275 的用户

我的查询是:

SELECT     u.id 
 FROM      user u 
 LEFT JOIN A a 
 ON        a.user_id = u.id
 LEFT JOIN B b 
 ON        b.user_id = u.id
 WHERE     a.partner_id = 275 
 OR        b.partner_id = 275
 GROUP BY  u.id 
 ORDER BY  u.id DESC 
 LIMIT     20

尽管我在表上创建索引,但查询速度很慢。 这里解释一下:

id : 1
select_type: SIMPLE
table: u
type: index
possible_keys: NULL
key: PRIMARY
key_len: 4
ref: NULL
rows: 20
Extra: Using index

我试图删除像这样的“或”边:

SELECT u.id FROM user u 
LEFT JOIN A a ON a.user_id = u.id
LEFT JOIN B b ON b.user_id = u.id
WHERE a.partner_id = 275
GROUP BY u.id ORDER BY u.id DESC LIMIT 20

要么

SELECT u.id FROM user u 
LEFT JOIN A a ON a.user_id = u.id
LEFT JOIN B b ON b.user_id = u.id
WHERE b.partner_id = 275
GROUP BY u.id ORDER BY u.id DESC LIMIT 20

两个查询都很快。 我不知道为什么?

我想要用户 ID,其中ab的合作伙伴为 275,您可以使用:

SELECT a.user_id
FROM A a
WHERE a.partner_id = 275
UNION 
SELECT b.user_id
FROM B b
WHERE b.partner_id = 275;
ORDER BY user_id DESC
LIMIT 20;

然后对于此查询,您需要A(partner_id, user_id)B(partner_id, user_id)上的索引。

据推测, OR条件正在破坏性能; 这是SQL中经常遇到的问题。

您可以尝试用两个exists条件来表达这一点; 这避免了外部聚合,并使意图更清晰:

select u.id
from user u
where exists (select 1 from a where a.user_id = u.id and a.partner_id = 275)
   or exists (select 1 from b where b.user_id = u.id and b.partner_id = 275)
order by u.id desc limit 20

这会带来在ab中与给定partner_id匹配的用户。

为了提高性能,您需要以下索引:

a(partner_id, user_id)
b(partner_id, user_id)

您可以尝试更改每个索引中列的顺序,看看是否有所不同。

如果您在两个表上有索引(例如,在 partner_id 上),使用它们的简单方法是将 OR 更改为UNIONUNION ALL 例如

SELECT     u.id 
  FROM     user u 
  WHERE    u.id IN
           (SELECT a.user_id
             FROM A a
             WHERE a.partner_id = 275
           UNION
           SELECT b.user_id
             FROM B b
             WHERE b.partner_id = 275
           )
 ORDER BY  u.id DESC 
 LIMIT     20;

我在这里使用了IN以提高可读性,但您可以使用LEFT JOIN ,如果您愿意,甚至可以使用EXISTS

上面的优点是每个 SELECT 都可以专门命中索引——而不是将查询计划生成与“或”混淆。

请注意,从技术上讲,您在这里也不需要user表(例如,您可以只使用 UNIONed 语句并从那里对 user_ids 进行排序 - 但我猜您可能还需要用户表中的其他信息。

如果WHERE条件引用 JOIN 左侧的列,则连接将转换为INNER JOIN 所以不需要LEFT JOIN 因为您需要找到“两个表上的合作伙伴 = 275...”的行,所以不需要OR条件。 像这样的东西。

select distinct u.id 
from [user] u 
     join a a on a.user_id = u.id
     join b b on b.user_id = u.id
where a.partner_id = 275 
      and b.partner_id = 275
order by u.id desc 
limit 20;

据推测,user.id 上有一个索引。 a 和 b 表将受益于覆盖 (user_id, partner_id) 的索引

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM