OR如果像这样包含在 where 子句中,我的查询的行为会非常不同
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'
Run Code Online (Sandbox Code Playgroud)
以上将在约 500 毫秒内运行。如果我删除 OR 并仅按用户 ID 进行过滤,如下所示:
WHERE u.id = '8601680c9cd549c0a786288e1775fb63'
Run Code Online (Sandbox Code Playgroud)
它运行时间为 20 毫秒。如果我只按团队 ID 进行过滤,如下所示:
WHERE t.id = '8601680c-9cd5-49c0-a786-288e1775fb63'
Run Code Online (Sandbox Code Playgroud)
它的运行时间也为 20 毫秒。但由于某种原因,如果我同时过滤,它会变得慢得多
有什么想法吗?
在许多情况下,这是因为解释计划无法轻松处理这两个条件。
要了解这一点或确定您需要查看所有三个解释计划,如果您希望我们弄清楚这一点,您需要在您的问题中提供它们。
ORt.idu.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'
Run Code Online (Sandbox Code Playgroud)
这也让LEFT OUTER JOINs变成了INNER JOINs。这是解释计划在第一个示例中会受到影响的示例;需要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'
Run Code Online (Sandbox Code Playgroud)
我还注意到您用于过滤表的列teams也是您从中选择的列。那么,您真的需要参考团队表吗(SELECT '8601680c-9cd5-49c0-a786-288e1775fb63' AS id UNION ...)? (或者您只是检查这样的团队是否存在?)