Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用IN-over-internaljoin优化Sql查询_Sql_Sql Server_Tsql - Fatal编程技术网

使用IN-over-internaljoin优化Sql查询

使用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: 问题:

鉴于:

表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:

问题:

在对这两个查询计时时,我发现在大型数据集上,使用
的第一个查询要比使用
内部联接的第二个查询快得多。我不明白为什么有人能帮我解释一下


您的第二个查询有点滑稽-您能试试这个吗

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
vs
28271800
for
JOIN
,被聚合的估计行数是
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)