原始查询我正在尝试重写:
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。我已更新上述查询以反映这一点。
答案 0 :(得分:2)
我相信你是正确的,因为嵌套的子查询导致你看到的统计数据。当你有一个转换成这样的集合的值时,我经常发现性能最佳的解决方案是将子查询的结果推送到临时表中,然后反而加入。这可以防止基于行的子查询执行,并且可以显着提高您的性能。
子查询的内容引用静态语句变量,但不引用外部语句中的任何元素。这意味着它不是一个相关的子查询,我们只是为每一行反复执行相同的操作。当你看到像这样的子查询时,这是一个简单的优化选择,可以在选择之外移动操作并以更合适的方式引用数据。
对于您提供的示例,您将执行类似
的操作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而异。