为什么在创建临时表的存储过程末尾截断临时表会更快地释放临时数据库空间?

Mar*_*man 12 sql-server stored-procedures truncate tempdb temporary-tables

SQL Server 缓存在存储过程中创建的临时表,并且仅在过程结束和随后执行时重命名它们。我的问题与 tempdb 空间何时被释放有关。我读到该表在程序结束时截断。我在评论中读到这是在每个会话的基础上处理的,并且在 MSDN看到了一个关于是否需要清理的问题。但是如果它从来没有被同一个会话执行过两次呢?

我还听说有一个后台垃圾收集进程,一旦表超出范围,就会释放该空间。

在创建它的存储过程结束时截断临时表似乎会导致表在 tempdb 中用于数据的空间比不使用 truncate 语句时释放的空间更快,尽管与预期相反。为什么?

使用或不使用这种截断语句的相对性能影响是什么?使用 SNAPSHOT 隔离时,tempdb 经常受到压力,我认为尽快从大型临时表中释放 tempdb 中使用的空间将防止 tempdb 不必要的增长。这种潜在的空间节省是否会以性能为代价?

这是一些重现问题的代码(主要来自@TheGameiswar,有一些更改):

SET NOCOUNT ON;
GO
ALTER PROC usp_test
AS
BEGIN
    IF object_id('tempdb..#temp') IS NOT NULL
        DROP TABLE #temp

    SELECT *
    INTO #temp
    FROM [dbo].[Event_28] -- This is a table with 15313 rows, using 35648 KB according to sp_spaceused

    --SELECT SUM(user_object_reserved_page_count) AS [user object pages used]
    --  ,(SUM(user_object_reserved_page_count) * 1.0 / 128) AS [user object space in MB]
    --  ,getdate() AS BeforeTruncate
    --FROM tempdb.sys.dm_db_file_space_usage;
 --   TRUNCATE TABLE #temp
    --SELECT SUM(user_object_reserved_page_count) AS [user object pages used]
    --  ,(SUM(user_object_reserved_page_count) * 1.0 / 128) AS [user object space in MB]
    --  ,getdate() AS AfterTruncate
    --FROM tempdb.sys.dm_db_file_space_usage;

END
GO

SELECT SUM(user_object_reserved_page_count) AS [user object pages used]
    ,(SUM(user_object_reserved_page_count) * 1.0 / 128) AS [user object space in MB]
    ,getdate() AS 'before'
FROM tempdb.sys.dm_db_file_space_usage;

EXEC usp_test
GO

SELECT SUM(user_object_reserved_page_count) AS [user object pages used]
    ,(SUM(user_object_reserved_page_count) * 1.0 / 128) AS [user object space in MB]
    ,getdate() AS 'final'
FROM tempdb.sys.dm_db_file_space_usage;
GO 40
Run Code Online (Sandbox Code Playgroud)

注释行在某些运行中被注释掉,而在其他运行中未注释。当TRUNCATE被注释掉时,在tempdb.sys.dm_db_file_space_usage查询结果(多 4472 页和 34.9375 MB)与执行过程之前的结果匹配之前需要 2.25 到 4.5 秒。TRUNCATE取消注释行(包括),只需要大约 0.11 - 0.9 秒。这些结果来自实时系统,在此实验期间源表中的数据略有增长。

代码注释掉的示例输出(从第一个“最终”条目到最后一个“最终”条目 2.69 秒):

user object pages used user object space in MB                 before
---------------------- --------------------------------------- -----------------------
1536                   12.000000                               2017-10-04 21:03:42.197

Beginning execution loop
user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:42.423

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:42.533

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:42.643

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:42.883

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:42.990

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:43.100

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:43.450

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:43.650

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:43.767

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:43.993

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:44.103

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:44.213

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:44.437

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:44.553

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:44.663

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:44.887

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6000                   46.875000                               2017-10-04 21:03:45.003

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
1536                   12.000000                               2017-10-04 21:03:45.113
Run Code Online (Sandbox Code Playgroud)

代码未注释的示例结果(从第一个“最终”条目到最后一个“最终”条目 0.11 秒):

user object pages used user object space in MB                 before
---------------------- --------------------------------------- -----------------------
1536                   12.000000                               2017-10-04 21:07:39.807

user object pages used user object space in MB                 BeforeTruncate
---------------------- --------------------------------------- -----------------------
6016                   47.000000                               2017-10-04 21:07:39.923

user object pages used user object space in MB                 AfterTruncate
---------------------- --------------------------------------- -----------------------
6016                   47.000000                               2017-10-04 21:07:39.923

Beginning execution loop
user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
6016                   47.000000                               2017-10-04 21:07:40.160

user object pages used user object space in MB                 final
---------------------- --------------------------------------- -----------------------
1536                   12.000000                               2017-10-04 21:07:40.270
Run Code Online (Sandbox Code Playgroud)

Pau*_*ite 12

在创建它的存储过程结束时截断临时表似乎会导致表在 tempdb 中用于数据的空间比不使用 truncate 语句时释放的空间更快,尽管与预期相反。为什么?

如果临时表足够大(超过 128 个盘区),物理页释放被推迟,并由后台系统任务执行。无论是否使用显式,TRUNCATE TABLE都是如此。

唯一的区别是一个微小的实现细节。一个显式TRUNCATE TABLE的任务恰好创建了一个计时器比临时表清理创建的(否则相同的)延迟删除任务更短的任务:

调用堆栈因为人们喜欢它们

这是偶然还是设计是任何人的猜测。它当然可以随时更改,因为这种详细程度远远超出了支持的产品表面积。

如果您使用(大部分)未记录的跟踪标志全局禁用延迟删除:

DBCC TRACEON (671, -1);
Run Code Online (Sandbox Code Playgroud)

...在这两种情况下,释放都是同步执行的,您不会看到时间上的差异。

使用或不使用这种截断语句的相对性能影响是什么?使用 SNAPSHOT 隔离时,tempdb 经常受到压力,我认为尽快从大型临时表中释放 tempdb 中使用的空间将防止 tempdb 不必要的增长。这种潜在的空间节省是否会以性能为代价?

我严重怀疑这无论哪种方式都会产生很大的不同。如果tempdb的大小适合您的工作负载的峰值需求,那么延迟下降是在一秒还是三秒后发生应该无关紧要。做同样的工作;这只是时间上的微小差异。

另一方面:如果您觉得TRUNCATE TABLE在存储过程结束时使用临时表更舒服,那就去吧。我不知道这样做有什么特别的缺点。