使用IN-over-internaljoin优化Sql查询
鉴于: 表y使用IN-over-internaljoin优化Sql查询,sql,sql-server,tsql,Sql,Sql Server,Tsql,鉴于: 表y id int聚集索引 name nvarchar(25) 另一张表 id int聚集索引 name nvarchar(25) 表格功能 进行一些数学运算,然后返回一个有效的ID 比较: SELECT y.name FROM y WHERE dbo.SomeFunction(y.id) IN (SELECT anotherTable.id FROM AnotherTable) vs: 问题:
id int聚集索引
name nvarchar(25)
id int聚集索引
name nvarchar(25)
- 进行一些数学运算,然后返回一个有效的ID
SELECT y.name
FROM y
WHERE dbo.SomeFunction(y.id) IN (SELECT anotherTable.id
FROM AnotherTable)
vs:
问题:
在对这两个查询计时时,我发现在大型数据集上,使用的第一个查询要比使用内部联接的第二个查询快得多。我不明白为什么有人能帮我解释一下
您的第二个查询有点滑稽-您能试试这个吗
SELECT y.name
FROM dbo.y
INNER JOIN dbo.AnotherTable a ON a.id = dbo.SomeFunction(y.id)
这有什么区别吗
否则:看看执行计划!可能把它们贴在这里。如果不了解更多关于表(数据量和分布等)和系统(RAM、磁盘等)的信息,就很难给出一个“全局”的答案有效语句一般来说,
中的与JOIN
不同,因为JOIN
可以返回额外的行,其中一行在JOIN
-ed表中有多个匹配项
从估计的执行计划可以看出,在本例中,这两个查询在语义上是相同的
SELECT
A.Col1
,dbo.Foo(A.Col1)
,MAX(A.Col2)
FROM A
WHERE dbo.Foo(A.Col1) IN (SELECT Col1 FROM B)
GROUP BY
A.Col1,
dbo.Foo(A.Col1)
对
SELECT
A.Col1
,dbo.Foo(A.Col1)
,MAX(A.Col2)
FROM A
JOIN B ON dbo.Foo(A.Col1) = B.Col1
GROUP BY
A.Col1,
dbo.Foo(A.Col1)
即使重复项是由联接引入的
也会被分组依据
删除,因为它只引用左侧表格中的列。此外,这些重复行不会改变结果,因为MAX(A.Col2)
不会改变。然而,并非所有骨料都是如此。如果要使用SUM(A.Col2)
(或AVG
或COUNT
),则重复项的存在将改变结果
SQL Server似乎没有任何逻辑来区分聚合(如MAX
)和聚合(如SUM
),因此很可能它正在扩展所有重复项,然后在以后聚合它们,并且只需做更多的工作
对于IN
vs28271800
forJOIN
,被聚合的估计行数是2893.54
,但是这些估计不一定非常可靠,因为JOIN谓词是不可组织的。好吧,首先:去掉dbo.SomeFunction(y.id)
隐含的标量UDF。即使用一行内联表值函数替换它,效果也会更好
至于你的实际问题,我在其他情况下也发现了类似的结果,同样感到困惑。优化器只是以不同的方式对待它们;我很想看看其他人提供了什么答案。请咨询优化器/解释计划-我们无法告诉您您的数据发生了什么。我不确定,但我猜这是因为在这种情况下,它会从另一个表中获得一次id列表,而在内部连接中,它必须有效地准备记录的完整外部产品,并检查每一个记录。您的函数调用阻止它自己进行任何优化。@gh9-明显的区别是
版本中的
对半联接执行哈希联接,而联接执行合并联接。您是否可以发布实际的计划,而不是估计的计划,以查看实际的行数。@gh9-由于实际查询中的GROUP BY
,因此查询的语义是它们都将返回相同的结果。我想知道联接是否最终扩展了处理的中间行数因为分组依据
,所以只能在稍后消除重复项。即使不是,也可以查看每个运算符与估计值之间的行数。@gh9-我将发布一个带有潜在解释的答案。我感谢您花时间解释,并在我上传信息时耐心等待。非常感谢+1个好建议:“隐含的标量UDF”——我没有立即发现;)
SELECT
A.Col1
,dbo.Foo(A.Col1)
,MAX(A.Col2)
FROM A
JOIN B ON dbo.Foo(A.Col1) = B.Col1
GROUP BY
A.Col1,
dbo.Foo(A.Col1)