大型表上的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件需要考虑的事情:
根据您的执行计划,这两个查询实际上都在扫描整个大表中的每条记录。。。第二个查询只是在扫描大表之前从小表中查找一小组记录,这就是为什么两者的相对成本都是50% 我建议考虑在
largeTable.SomeId
上建立索引,然后执行第一个查询:
SELECT lt.* FROM LargeTable lt
WHERE lt.SomeId in(12,55)
编辑:
所以最大的问题是,为什么带有连接的查询的持续时间比没有连接的查询的持续时间短
我认为马丁·史密斯回答了这个问题:
你的第二个有一个平行的计划第一个没有 您会注意到,第一个查询的CPU时间较短,但运行时间较长。粗略地总结一下,第一个查询完成服务器所需的工作量较少,但第二个查询使用了并行计划,并使用多个处理器来执行查询,因此完成查询所需的时间较少,但总体工作量较大
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)
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)的类比。就是这样!感谢你看了我的实际问题。