Sql server 当与IN子句一起使用时,未绑定的结果集是否比带有联接的查询性能更好?

Sql server 当与IN子句一起使用时,未绑定的结果集是否比带有联接的查询性能更好?,sql-server,performance,Sql Server,Performance,对于IN子句中的子查询,我最好返回大量结果(10000多行)还是使用表连接来限制结果 例如: select * from Units u inner join pm_Properties p on p.PropertyId = u.PropertyId where p.State = 'CA' and u.UnitId in (select UnitId from Leases l where l.IsActive = 1) vs 在这两种情况下,我都希望返回与属性关联的单位结果。

对于IN子句中的子查询,我最好返回大量结果(10000多行)还是使用表连接来限制结果

例如:

select * from Units u
  inner join pm_Properties p on p.PropertyId = u.PropertyId
  where p.State = 'CA'
  and u.UnitId in (select UnitId from Leases l where l.IsActive = 1)
vs


在这两种情况下,我都希望返回与属性关联的单位结果。我只是好奇关于IN声明的性能差异。此外,如果有必要的话,服务器是MS SQL 2008 R2。

我认为让优化器完成其工作的最有效方法是使用子查询避免两个版本。为什么不是这个

SELECT * 
  FROM Units AS u
  INNER JOIN pm_Properties AS p
  ON p.PropertyId = u.PropertyId
  INNER JOIN Leases AS l
  ON l.UnitId = u.UnitId
  AND l.IsActive = 1
  WHERE p.State = 'CA';
根据JNK的建议,另一个备选方案如下(但正如我所建议的,如果CA中有很大一部分不在CA中,可能会有大量I/O检查有效租约):

当然,您知道您的数据、索引、硬件、使用模式等。确定哪条路线“更好”的最有效方法是自己测试它们——这将为您提供比您在这里询问的任何人都更可靠的答案。没有冒犯任何人的意思,但有太多的变量,无法作出全面的声明

还有-这只是一个nit-制作一个表别名Units->unit有什么意义?您键入了4个额外字符以避免键入一个字符-如果您计划在查询中引用单位超过4次,这可能是有意义的,但特别是在这种情况下,我宁愿使用更短的别名。

使用第一个(除非您因某种原因出现性能问题)


第二种方法是提供SQL server能够自行计算的冗余信息—您所做的只是增加查询的复杂性,增加计算执行计划的成本,并增加它无法找到最佳计划的可能性。

正如JNK所暗示的,这要视情况而定

这取决于联接条件的复杂程度,以及每个表相对于其他表的行数。我认为在“正常”情况下,您的第一个例子中没有in子句中的连接会更快,但这会因我提到的因素而有所不同


所以,如果您真的试图绝对优化性能,我将测试它们,并将适合您特定情况的更好的结果投入生产。但是,如果它们甚至很接近,我会非常喜欢第一个(我认为在大多数用例中都会赢)。优化器更容易使用,更重要的是,它更容易阅读,这意味着它更容易维护。

根据我的经验,如果不从表中返回任何字段,在或
中存在一个
子查询
对于这样的事情来说速度更快…它还避免了在
JOIN
ed表中重复行导致输出重复的问题在这种情况下,我可能同意你的看法,但问题中所写的更简单的版本有可能实现许多不在加利福尼亚州的租赁。再次解释为什么我更新了我的问题,并在模式、索引、数据上声明“这取决于”免责声明……是的,我同意。每一个案例都没有答案。我想我们需要一个键盘快捷键,这取决于它是否被添加到SO GUI。@gbn,我假设(和op确认)他们实际上没有使用SELECT*。因此,如果实际需要的列表达正确,它们将不会是不同的查询。请养成在所有列引用前加前缀的习惯,即使它们当前只能来自一个表。“
和UnitId in
”应该是“
和unit.UnitId in
”或“
和Units.UnitId in
”-现在对您来说可能很明显,但稍后当其他人进行故障排除时,他们必须进行反向工程。。。如果向查询中添加更多表,则无需担心,如果任何新表具有相同的列名,则必须返回并添加前缀。(对不起,如果我要宣传最佳实践,我不能忽略这一点-您不会真的将SELECT*推到生产中,是吗?@aaron感谢您的建议。我已经把样品清理干净了code@aaron不,我的程序中的sql代码基本上是用ORM从我这里抽象出来的,它显式地指定了每一列。选择*在这里写起来更快。
SELECT * 
  FROM Units AS u
  INNER JOIN pm_Properties AS p
  ON p.PropertyId = u.PropertyId
  INNER JOIN Leases AS l
  ON l.UnitId = u.UnitId
  AND l.IsActive = 1
  WHERE p.State = 'CA';
SELECT *
    FROM Units AS u
    INNER JOIN pm_Properties AS p
    ON p.PropertyId = u.PropertyId
    WHERE p.State = 'CA'
    AND EXISTS
    (
      SELECT 1 FROM Leases AS l
         WHERE l.UnitId = u.UnitId
         AND l.IsActive = 1
    );