大表上的SQL WHERE - >首先加入小表或直接将FK放在WHERE子句中?

时间:2011-12-21 16:11:04

标签: sql sql-server-2008 tsql

WHERE条款有什么好处?

我有一张大桌子,FK到一张小桌子。我可以直接搜索FK,或者我可以加入FK表并在连接表上设置WHERE限制。什么是更好/更好?

所以这个:

SELECT lt.* FROM LargeTable lt 
WHERE lt.SomeId in(12,55)

或者这个:

SELECT lt.* FROM LargeTable lt 
INNER JOIN SmallTable st ON lt.SomeId=st.ItemId
WHERE st.Id in(12,55)


我用Set statistics time on对此进行了测试,但我没想到会出现这种情况。谁能解释一下这里发生了什么?

没有加入的第一次测试:

(946 row(s) affected)
 SQL Server Execution Times:
   CPU time = 1544 ms,  elapsed time = 1580 ms.

使用连接进行第二次测试

(946 row(s) affected)
 SQL Server Execution Times:
   CPU time = 2636 ms,  elapsed time = 366 ms.

编辑:当我执行SELECT Id而不是SELECT *时,没有连接的第一个查询的已用时间会更短,执行计划中的查询成本为25%(无连接)和75%对于带有连接的查询。

3 个答案:

答案 0 :(得分:4)

根据你的执行计划,两个查询基本上扫描整个大表中的每个记录......第二个查询只是在扫描大表之前从小表中查找一小组记录,这就是为什么相对两者的成本都是50%。

我建议考虑largeTable.SomeId上的索引,然后使用第一个查询:

SELECT lt.* FROM LargeTable lt 
WHERE lt.SomeId in(12,55)

编辑:

所以最大的问题是为什么连接的查询持续时间比没有连接的查询的持续时间短。

我认为马丁史密斯给出了这个问题的答案:

  

你的第二个获得并行计划,第一个没有

您会注意到您的第一个查询的CPU时间较短,但经过的时间较长。粗略地总结一下,您的第一个查询花费了较少的时间来完成服务器,但是您的第二个查询使用了并行计划,并且使用了多个处理器来执行查询,因此完成所需的时间更少,但总体工作量更大。

答案 1 :(得分:0)

要考虑的两件事:

     
  1. 您的内连接是否返回了一组较小的数据?在这种情况下,您的where条件在较少的行上执行。  
  2.  
  3.   我想在你的第二个查询中你想说其中st.Id在(12,55),在这种情况下,你的where子句是针对一个主键索引运行的,因为它比一个主键索引更快您的非群集外键索引  

答案 2 :(得分:0)

  1. 因为两个查询都是从提到的大表中提取结果。那么,您对“SomeID”列有 Non clustered Index 吗?

  2. 您使用的是此表中的所有列吗?如果不是这样的话。建议仅提及所需的列。

  3. 由于这两个查询都是从大表中提取数据所以只能通过“非聚集索引

  4. ”从第一次查询中完成。

  5. 如果有任何案例只能获得匹配的数据。然后你也可以这样做。

    Select ColumnName From
    (
     Select ColumnName, SomeID from LargeTable Where SomeID in(12,13)
    )T
    Inner Join SmallTable T1 on T.SomeID = T1.SomeID
    
  6. 如果您想要非常快速的结果。你可以这样做。

    Create table #Large
    (
      Id Int,
      ColumnName Varchar(100)
    )
    Insert into #Large(ID, ColumnNmae)
    Select ColumnName, SomeID from LargeTable Where SomeID in(12,13)
    
  7. 最后加入

    Select ColumnName From #Large T
    Inner Join SmallTable T1 on T.SomeID = T1.SomeID
    

    且没有加入

    Select ColumnName from #Large