如果像这样在 where 子句中包含 OR
,我有这个查询,它的行为非常不同
SELECT t.id
FROM teams AS t
LEFT OUTER JOIN teams_users AS tu ON tu.team_id = t.id
LEFT OUTER JOIN user AS u ON tu.user_id = u.id
WHERE
u.id = '8601680c9cd549c0a786288e1775fb63' OR t.id = '8601680c-9cd5-49c0-a786-288e1775fb63'
以上将在 ~500 毫秒内运行。如果我删除 OR 并仅按用户 ID 进行过滤,如下所示:
WHERE u.id = '8601680c9cd549c0a786288e1775fb63'
它在 20 毫秒内运行。如果我像这样只按团队 ID 过滤:
WHERE t.id = '8601680c-9cd5-49c0-a786-288e1775fb63'
它也在 20 毫秒内运行。但出于某种原因,如果我同时过滤两者,它会变得更慢
关于原因有什么想法吗?
最佳答案
在许多情况下,这是因为解释计划无法轻松处理这两种情况。
- 针对一种情况的最佳计划与针对另一种情况的计划会有很大不同。
要知道或确定您需要查看所有三个解释计划,如果您希望我们弄清楚,您需要在问题中提供它们。
- 您使用
OR
进行主查询 - 仅根据
t.id
过滤 - 仅根据
u.id
过滤
使用 IN()
的示例避免了键入关键字 OR
,但仍会产生相同的逻辑并且通常容易出现相同的规划问题。
如果是这种情况,一种选择是使用 UNION
。这允许您的结果包含来自两个单独查询的结果,DBMS 可以单独计划...
SELECT t.id
FROM teams AS t
WHERE t.id = '8601680c-9cd5-49c0-a786-288e1775fb63'
UNION
SELECT t.id
FROM teams AS t
INNER JOIN teams_users AS tu ON tu.team_id = t.id
INNER JOIN user AS u ON tu.user_id = u.id
WHERE u.id = '8601680c9cd549c0a786288e1775fb63'
这也允许 LEFT OUTER JOIN
变成 INNER JOIN
。这是解释计划在您的第一个示例中受到影响的示例;需要 LEFT JOIN
只是因为您想解决这两个条件,但允许分别解决它们允许 INNER JOIN
。
您还可以在第二个查询中删除对 teams
的连接,然后从 tu.team_id AS id
中选择...
编辑:
SELECT id
FROM teams
WHERE id = '8601680c-9cd5-49c0-a786-288e1775fb63'
UNION
SELECT team_id
FROM teams_users
WHERE user_id = '8601680c9cd549c0a786288e1775fb63'
我还注意到,您过滤 teams
表所依据的列也是您从中选择的列。那么,您是否真的需要完全引用团队表(SELECT '8601680c-9cd5-49c0-a786-288e1775fb63' AS id UNION ...)
? (或者您只是在检查这样的团队是否存在?)
关于sql - OR 语句大大减慢了查询速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48984162/