【问题标题】:Rewriting sql query with a nested subquery用嵌套子查询重写 sql 查询
【发布时间】:2011-10-24 00:06:34
【问题描述】:

我正在尝试重写的原始查询:

SELECT Table1.* 
FROM Table1
INNER JOIN Table2 ON Table2.[IDENTITY]=Table1.ID
WHERE Table2.Field1 = @value AND Table2.Field2 = '1' AND Table1.ID in
(
   select Table1.ID from Table1 where Table1.Number in
   (select Table1.Number from Table1 where Table1.ID=@ID) 
)

注意:在实际查询中,我列出了所有列,而不是使用 Table1.*

这个查询有点令人困惑,特别是因为我更改了名称等以进行发布。简而言之,它需要获取传入的 ID 并查找具有该 ID 的所有 Table1.Number 字段。 Number 和 ID 之间存在多对一的关系。因此,一旦找到所有数字,我就需要找到使用任何这些数字的 ID 的总列表。

当我运行查询时查看统计信息时,我得到了

Table 'Table1'. Scan count 3873, logical reads 135255, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Table2'. Scan count 0, logical reads 7995, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

我觉得罪魁祸首是嵌套子查询。一段时间以来,我一直在尝试以不同的方式编写此代码,但我似乎无法完全弄清楚。我将第二个嵌套查询重写为:

WHERE Table2.Field1 = @value AND Table2.Field2 = '1' AND Table1.ID in
(
   select Table1.ID from Table1
   INNER JOIN Table1 AS Table3 ON Table1.Number = Table3.Number 
   where Table3.MessageID=@ID
)

不幸的是,这导致了相同的统计数据。我不太清楚如何删除第二个“in”语句。

这是最好的方法吗?有更好的吗?这种子查询在性能方面非常糟糕,因此会导致 IO 统计数据显示给我的高扫描和逻辑读取,我对吗?

编辑:原始查询使用 Table2.[IDENTITY]=Table1.MessageID。那应该是 Table2.[IDENTITY]=Table1.ID。我已更新上述查询以反映这一点。

【问题讨论】:

    标签: sql query-optimization


    【解决方案1】:

    我相信您是正确的,因为嵌套子查询会导致您看到的统计信息。当你有一个值被转换成这样的集合时,我经常发现最好的解决方案是将子查询的结果推送到一个临时表中,然后加入它。这可以防止子查询的基于行的执行,并应显着提高您的性能。

    子查询的内容引用一个静态语句变量,但不引用外部语句中的任何元素。这意味着它不是一个相关的子查询,我们只是对每一行反复执行相同的操作。当您看到这样的子查询时,将操作移到选择之外并以更合适的方式引用数据是一个简单的优化选择。

    对于您提供的示例,您可以执行类似

    的操作
    select distinct Table1.ID 
    INTO #myTemp
    from Table1 where Table1.Number in
    (select Table1.Number from Table1 where Table1.ID=@ID) 
    

    这会将您的初始查询变成

    SELECT Table1.* 
    FROM Table1
    INNER JOIN Table2 ON Table2.[IDENTITY]=Table1.MessageID
    INNER JOIN #myTemp a on Table1.ID = a.ID
    WHERE Table2.Field1 = @value AND Table2.Field2 = '1' 
    

    我假设您使用的是 SQL2008 R2,因此您的语法可能会因您的 RDBMS 而异。

    【讨论】:

    • 感谢您的帮助。在我的原始帖子中发现了一个小错字(MessageID 应该是 ID)。您的更改使我减少到 1 次扫描和 1110 次逻辑读取。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多