[英]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,其中a
或b
的合作伙伴为 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
这会带来在a
或b
中与给定partner_id
匹配的用户。
为了提高性能,您需要以下索引:
a(partner_id, user_id)
b(partner_id, user_id)
您可以尝试更改每个索引中列的顺序,看看是否有所不同。
如果您在两个表上有索引(例如,在 partner_id 上),使用它们的简单方法是将 OR 更改为UNION
或UNION 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.