【问题标题】:TSQL Operators IN vs INNER JOINSQL 运算符 IN 与 INNER JOIN
【发布时间】:2016-07-26 13:58:59
【问题描述】:

使用 SQL Server 2014:

以下语句之间是否存在性能差异?

DELETE FROM MyTable where PKID IN (SELECT PKID FROM @TmpTableVar)

DELETE FROM MyTable INNER JOIN @TmpTableVar t ON MyTable.PKID = t.PKID

【问题讨论】:

  • 查看每个的执行计划。在这种情况下,它们很可能是相同的。
  • 执行计划基于当前统计。它们今天可能相同,但以后会改变。这就是我寻找更广泛规则的原因。
  • 我做了一些测试,几乎在所有情况下都相似stackoverflow.com/questions/38444729/…
  • 澄清一下:EXPLAIN 动词用于获取执行计划信息。
  • 但即使使用不同的统计信息,运行时的统计信息也是相同的。不确定您所说的更广泛的规则是什么意思??

标签: sql-server tsql


【解决方案1】:

在您给定的示例中,执行计划将是相同的(很可能)。

但具有相同的执行计划并不意味着它们是您可能拥有的该语句的最佳执行计划。

我在您的两个查询中看到的问题是使用了Table Variable

SQL Server 始终假定表变量中只有 1 行。仅在 SQL Server 2014 及更高版本中,此假设已更改为 100 行。

因此,无论您有多少行,SQL Server 表变量都将始终假定您在@TmpTableVar 中有一行。

您可以稍微更改您的代码,让 SQL Server 更好地了解该表中有多少行,方法是将其替换为 Temporary table,因为它是表变量中的 PK_ID 列,您还可以在该表上创建一个索引,以使 sql server 有最好的机会为此查询提出最佳执行计划。

SELECT PKID INTO #Temp
FROM @TmpTableVar

-- Create some index on the temp table here .....

DELETE FROM MyTable
WHERE EXISTS (SELECT 1 
              FROM #Temp t
              WHERE MyTable.PKID = t.PKID)

注意

In 运算符可以正常工作,因为它是表变量中的主键列。但是,如果您曾经在可为空的列上使用 IN 运算符,结果可能会让您感到惊讶,IN 运算符一旦在它正在检查的列中找到 NULL 值,就会变成梨形。

对于此类查询,我个人更喜欢 Exists 运算符,但内部联接也应该可以正常工作,但如果可以,请避免使用 IN 运算符。

【讨论】:

  • 感谢您的帮助。 @tableVariables 所关注的行数是否也适用于内部连接方法?我正在考虑将内部连接视为更安全的方法。
  • 不是问题,是的,它会导致 sql server 提出效率较低的执行计划,因为 sql server 假设该表中只有一行,主键列上的连接应该带来只退一排。但事实并非如此,因此避免在这种情况下使用表变量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-02
  • 1970-01-01
  • 2013-07-19
  • 2017-05-27
  • 1970-01-01
  • 2023-03-31
  • 2016-12-23
相关资源
最近更新 更多