Sql 为什么选择临时表然后合并并不比从源查询合并慢?
下面是一个使用表值函数结果的合并:Sql 为什么选择临时表然后合并并不比从源查询合并慢?,sql,sql-server,tsql,query-optimization,Sql,Sql Server,Tsql,Query Optimization,下面是一个使用表值函数结果的合并: MERGE Table1 d USING dbo.tvf_Table1(@StartDate, @EndDate) s ON d.ID = s.ID WHEN MATCHED THEN UPDATE SET Dest1 = Src1, Dest2 = Src2, Dest3 = Src3 WHEN NOT MATCHED THEN INSERT VALUES(ID, Src1, Src2, Src3); 在我的环境中,大约需要
MERGE
Table1 d
USING
dbo.tvf_Table1(@StartDate, @EndDate) s ON d.ID = s.ID
WHEN MATCHED THEN UPDATE
SET Dest1 = Src1, Dest2 = Src2, Dest3 = Src3
WHEN NOT MATCHED THEN INSERT
VALUES(ID, Src1, Src2, Src3);
在我的环境中,大约需要30秒(平均三次运行)
下面是相同的合并,但这次先将函数结果放入临时表:
SELECT
*
INTO
#Temp1
FROM
dbo.tvf_Table1(@StartDate, @EndDate)
MERGE
Table1 d
USING
#Temp1 s ON d.ID = s.ID
WHEN MATCHED THEN UPDATE
SET Dest1 = Src1, Dest2 = Src2, Dest3 = Src3
WHEN NOT MATCHED THEN INSERT
VALUES(ID, Src1, Src2, Src3);
DROP TABLE #Temp1
大约用了31秒(平均三次跑步)
事实上,使用临时表运行54次以上的合并比不使用临时表快大约4分钟
接受这几乎不科学的观点,我本以为添加临时表步骤会显著降低查询速度。毕竟,数据是从A移动到B,然后从B移动到C,而不是直接从A移动到C
幕后发生了什么可能导致这种情况?如果放入临时表的数据量不太大,服务器应该能够将其全部保存在内存中,而不必将其溢出到磁盘。因此,
B
在您的A
->B
中,B
->C
与C
(可能还有A
)相比,访问成本非常低廉。通常情况下,在直接的查询中,I/O成本会超过大多数其他成本
从总体上看,如果单个
合并的性能足够好,我还是更喜欢它。不要试图通过将任务分解为一系列子任务来帮助SQL Server—这是优化器的工作,虽然它可能并不总是选择一个最佳计划,但它通常会选择一个足够好的计划。如果临时表中的数据量不太大,服务器应该能够将其全部保存在内存中,而不必将其溢出到磁盘。因此,B
在您的A
->B
中,B
->C
与C
(可能还有A
)相比,访问成本非常低廉。通常情况下,在直接的查询中,I/O成本会超过大多数其他成本
从总体上看,如果单个合并的性能足够好,我还是更喜欢它。不要试图通过将任务分解为一系列子任务来帮助SQL Server—这是优化器的工作,虽然它可能并不总是选择一个最佳计划,但通常会选择一个足够好的计划。临时表为优化器提供了比表值函数更多的优化信息
我可以理解,您希望写入表的开销会降低总体速度。但是,合并查询的其余部分也需要优化,了解表的确切大小有助于优化器改进总体计划。临时表为优化器提供了比表值函数更多的优化信息
我可以理解,您希望写入表的开销会降低总体速度。但是,合并查询的其余部分也需要优化,知道表的确切大小有助于优化器改进总体计划。您是在运行整个脚本(即插入临时表以及合并),还是只运行合并?因为如果只是合并,很容易理解为什么它更快…整个脚本一起创建表,运行合并并在一个目标中删除表您运行整个脚本(意味着插入临时表以及合并),还是只运行合并?因为如果只是合并,很容易理解为什么它更快…整个脚本一起创建表,运行合并,一次删除表。感谢这个措辞精良、易于理解的答案。另一个有更多的投票,但对我来说,这提供了一个更全面的解释。这个建议也很有帮助。谢谢你这个措辞精练、易懂的答案。另一个有更多的投票,但对我来说,这提供了一个更全面的解释。这个建议也很有帮助。