Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.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
大型表上的SQL WHERE->;先连接到小表,还是将FK直接放在WHERE子句中?_Sql_Sql Server 2008_Tsql - Fatal编程技术网

大型表上的SQL WHERE->;先连接到小表,还是将FK直接放在WHERE子句中?

大型表上的SQL WHERE->;先连接到小表,还是将FK直接放在WHERE子句中?,sql,sql-server-2008,tsql,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

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)

我用设置统计时间对其进行了测试,但我没有预料到结果会是这样。谁能解释这里发生了什么

无连接的首次测试:

(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%。

2件需要考虑的事情:

  • 您的内部联接是否返回较小的数据集?在这种情况下,where条件在较少的行上执行。
  • 我认为在您的第二个查询中,您的意思是说(12,55)中的where st.Id,在这种情况下,where子句针对的主键索引是聚集的,因此比非聚集外键索引快得多

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

    我建议考虑在
    largeTable.SomeId
    上建立索引,然后执行第一个查询:

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

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

    我认为马丁·史密斯回答了这个问题:


    你的第二个有一个平行的计划第一个没有

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

  • 因为两个查询都是从前面提到的大表中提取结果。那么,“SomeID”列有

  • 您正在使用此表中的所有列。如果不是这样的话。建议仅提及所需的列

  • 由于这两个查询都是从大表中提取数据,因此只能通过“非聚集索引”从第一个查询中完成

  • 如果有任何情况,仅获取匹配的数据。然后你也可以像下面这样做

    Select ColumnName From
    (
     Select ColumnName, SomeID from LargeTable Where SomeID in(12,13)
    )T
    Inner Join SmallTable T1 on T.SomeID = T1.SomeID
    
  • 如果你想要很快的结果。你可以像下面这样做

    Create table #Large
    (
      Id Int,
      ColumnName Varchar(100)
    )
    Insert into #Large(ID, ColumnNmae)
    Select ColumnName, SomeID from LargeTable Where SomeID in(12,13)
    
  • 最后是join

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

    Select ColumnName from #Large
    

    您应该包括实际的执行计划,然后并排运行这两个查询。。。SQL Server将告诉您哪个更快,以及为什么更快。实际执行计划为+1。不需要猜测。@RedFilter:不需要,但如果有必要,我可以包含索引。@MichaelFredrickson:执行计划非常简单。没有连接只是聚集索引扫描(100%)。With join也是一个聚集索引扫描(98%)和一个小表上的聚集索引搜索,以散列匹配的方式进行。这两种方法相对于批处理的查询成本都是50%。第二种方法得到一个并行计划,而第一种方法没有。1:两种方法都给我946行(见问题)。2:是的,我的意思是,我修改了问题!(我的测试很好,tho)最后两者都给出了946,但是在你到达where子句之前,你的结果集缩小了吗?如果lt.SomeId可为null,则会发生这种情况,在这种情况下,where子句不会对没有lt.SomeId的所有记录求值。如果它不可为null,那么唯一剩下的就是第二个点(对主键的搜索比对外键的搜索要快,即使在加入连接成本之后也是如此,但是它们会给出相同的结果吗?表1中是否可能有一条id为12的记录,而表2中没有?这两个查询在功能上是不同的。在第二个查询中,数据必须存在于两个表中在第一个查询中只有一个表。@HLGEM where子句中的列是外键,因此第二个表中必须存在记录,因此两个查询本质上是相同的-如果您已经知道ID,并且不需要信息(或将行限制在某个位置)为什么要加入呢?当然,如果你只是因为之前的某个时候把id拉了出来而得到了id(比如
    选择id WHERE key=@input
    ),您可能想重构它…@X-Zero:这是我的第一个想法,但后来我遇到了意想不到的情况,所以我想知道什么会更好/更快。我将添加一个索引并忘记连接,但我只是想知道为什么。@ErikDekker-这应该不仅仅从性能角度考虑(由于明显的“不相关”原因,可能会发生意外的变化);如果您要加入一个表,我希望它对上下文很重要,因为您试图限制(或增加)以某种方式显示结果,或者检索一些数据。如果这两项都没有明显完成,可能会造成令人担忧的混乱,因为遗漏了某些内容。这要归功于马丁·史密斯(Martin Smith)的类比。就是这样!感谢你看了我的实际问题。