为什么在存储过程的末尾截断临时表以更快地创建其可用的tempdb空间?


12

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

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

尽管有相反的预期,但在创建存储过程的末尾截断一个临时表时,似乎导致该表在tempdb中用于释放数据的空间比没有使用truncate语句时要快。为什么?

使用或不使用这样的截断语句对性能的影响是什么?使用SNAPSHOT隔离时,经常会感到tempdb压力,我认为尽快从大型temp表中释放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

已注释的行在某些运行中已被注释掉,而在另一些运行中未注释。当TRUNCATE被注释掉,它的结果之前,花了2.25秒和4.5之间tempdb.sys.dm_db_file_space_usage在执行过程之前匹配结果查询(4472多个页面以及34.9375 MB大)。在TRUNCATE未注释行(包括)的情况下,仅花费了大约0.11-0.9秒。这些结果来自实时系统,在此实验期间,源表中的数据有少量增长。

示例输出中的代码已被注释掉(从第一个“ final”条目到最后一个“ final”条目为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

代码未注释的示例结果(从第一个“ final”项到最后一个“ final”项的时间为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

Answers:


12

尽管有相反的预期,但在创建存储过程的末尾截断一个临时表时,似乎导致该表在tempdb中用于释放数据的空间比没有使用truncate语句时要快。为什么?

如果临时表足够大(超过128个扩展盘区),则将物理页面取消分配推迟,并由后台系统任务执行。无论是否使用显式TRUNCATE TABLE都是如此。

唯一的区别是实现细节很小。一个显式的TRUNCATE TABLE事情是创建一个比使用临时表清理创建的(否则是相同的)延迟放置任务的计时器更短的计时器

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

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

如果您使用(主要是)未记录的跟踪标志全局禁用延迟丢弃:

DBCC TRACEON (671, -1);

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

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

我严重怀疑这是否会在任何方面产生很大的不同。如果tempdb的大小适合您的工作量的峰值需求,则延迟下降在一秒钟还是三秒钟之后发生都不会有影响。完成了相同的工作;时间上的差别很小。

另一方面:如果TRUNCATE TABLE在存储过程结束时在临时表上使用时感觉更舒适,那就去吧。我不知道这样做的任何不利之处。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.