【问题标题】:stackoverflow db schema - multi-column join SLOW with EXISTSstackoverflow db schema - 多列加入慢与 EXISTS
【发布时间】:2022-01-06 12:16:00
【问题描述】:

我正在做一些性能测试,StackOverflow2010 DB 非常适合。

在这里测试多列连接SQL WHERE.. IN clause multiple columns

StackOverflow 数据库可在此处获得:https://www.brentozar.com/archive/2015/10/how-to-download-the-stack-overflow-database-via-bittorrent/

我正在尝试查询特定用户的帖子评论:

-- get users id < 5
SELECT *
FROM [Users]
WHERE Id < 5;

-- get posts for those users
SELECT *
FROM [Posts]
WHERE [OwnerUserId] IN (SELECT [Id] FROM [Users] WHERE Id < 5);

-- get comments for these posts 
SELECT *
FROM [Comments]
WHERE [PostId] IN (SELECT [Id]
                   FROM [Posts]
                   WHERE [OwnerUserId] IN (SELECT [Id] FROM [Users] WHERE Id < 5))
  AND [UserId] IN (SELECT [OwnerUserId]
                   FROM [Posts]
                   WHERE [OwnerUserId] IN (SELECT [Id] FROM [Users] WHERE Id < 5));

-- THIS version seems to select ALL comments and takes forever!
SELECT *
FROM [Comments]
WHERE EXISTS (SELECT *
              FROM [Posts]
              WHERE [OwnerUserId] IN (SELECT [Id] FROM [Users] WHERE Id < 5));

IN 查询有效,但它选择了一些 OwnerUserId 没有创建的评论(孤儿)。

EXISTS 查询(这似乎是正确的方法)似乎选择了 ALL cmets 并且需要永远!

有什么想法吗?原因在这里解释:https://sproket.github.io/Persism/n+1.html

【问题讨论】:

  • EXISTS 中的子查询不相关。因此,它返回表Comments中的每一行,因为EXISTS中的查询将找到至少一行存在。事实上,没有一个子查询是相关的。
  • 您是否尝试过执行实际的 JOIN 而不是 EXISTS/IN 查询?另外,为什么AND [UserId] IN (&lt;double nested subquery&gt;) 而不是AND [UserId] &lt; 5
  • @Larnu 我添加了一个链接来解释推理。这一切都适用于单列连接。
  • 如果信息与问题相关,请将其放在问题中,@sproketboy 。不要要求用户访问 Git 存储库的链接才能理解问题。
  • @Larnu 好的,我会再次询问这个问题并提供更多信息。

标签: sql-server database


【解决方案1】:

您在这里使问题过于复杂化。

首先,让我们看看您的第二个查询。这实际上根本不需要引用Users 表。您正在查找用户 ID Posts 表 OwnerUserId 中的帖子的详细信息。所以你可以把你的第二个查询写成:

SELECT *
FROM dbo.Posts
WHERE OwnerUserId < 5;

对于您的下一个查询,同样适用,您不需要子查询,用户的 ID 已经在 Comments 表中:

SELECT *
FROM dbo.Comments
WHERE UserId < 5;

至于您的EXISTS,它不起作用的原因是它不相关。因此,EXISTS always 中的子查询至少返回一行,因此 EXISTS 的计算结果为 TRUE;所以 每一Comments 的行都会被返回。

相关查询看起来像这样(这与您的查询无关,因为它们过于复杂):

SELECT {Columns}
FROM dbo.SomeTable ST
WHERE EXISTS (SELECT 1
              FROM dbo.OtherTable OT
              WHERE OT.OtherInt > 10
                AND OT.SomeID = ST.ID);

注意OT.SomeID = ST.ID 子句,这意味着表dbo.SomeTabledbo.OtherTable 有一些关系。因此,上述查询只会返回来自dbo.SomeTable 的行,其中dbo.OtherTable 中存在相关行并且该相关行在OtherInt 列中的值大于10。 p>

【讨论】:

  • 复杂的原因是这些查询需要被概括为我的 Persism 库的一部分。在 IN 中使用单列连接可以让我快速获取子行,同时避免 SELECT N+1 问题。
  • 就像我提到的那样,这些子查询在上述任何尝试中都不需要,@sproketboy。也许问题在于您使用了一个糟糕的示例来展示您实际上想要实现的目标,这导致您编写了不正确且过于复杂的 SQL。如果是这样,您可能需要提出一个新问题,详细说明您的实际问题。
猜你喜欢
  • 2011-11-06
  • 1970-01-01
  • 1970-01-01
  • 2013-09-30
  • 2018-11-02
  • 1970-01-01
  • 2019-05-14
  • 2020-11-25
  • 2021-01-10
相关资源
最近更新 更多