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—这是优化器的工作,虽然它可能并不总是选择一个最佳计划,但通常会选择一个足够好的计划。

临时表为优化器提供了比表值函数更多的优化信息


我可以理解,您希望写入表的开销会降低总体速度。但是,合并查询的其余部分也需要优化,了解表的确切大小有助于优化器改进总体计划。

临时表为优化器提供了比表值函数更多的优化信息


我可以理解,您希望写入表的开销会降低总体速度。但是,合并查询的其余部分也需要优化,知道表的确切大小有助于优化器改进总体计划。

您是在运行整个脚本(即插入临时表以及合并),还是只运行合并?因为如果只是合并,很容易理解为什么它更快…整个脚本一起创建表,运行合并并在一个目标中删除表您运行整个脚本(意味着插入临时表以及合并),还是只运行合并?因为如果只是合并,很容易理解为什么它更快…整个脚本一起创建表,运行合并,一次删除表。感谢这个措辞精良、易于理解的答案。另一个有更多的投票,但对我来说,这提供了一个更全面的解释。这个建议也很有帮助。谢谢你这个措辞精练、易懂的答案。另一个有更多的投票,但对我来说,这提供了一个更全面的解释。这个建议也很有帮助。