Warum wird eine temporäre Tabelle am Ende der gespeicherten Prozedur abgeschnitten, wodurch schneller freier temporärer Speicherplatz erstellt wird?

12

SQL Server speichert temporäre Tabellen zwischen, die in gespeicherten Prozeduren erstellt wurden, und benennt sie nur um, wenn die Prozedur endet und anschließend ausgeführt wird. Meine Frage hat damit zu tun, wann der Tempdb-Speicherplatz freigegeben wird. Ich habe gelesen, dass die Tabelle am Ende des Vorgangs abgeschnitten wird . Ich habe in Kommentaren gelesen, dass dies pro Sitzung gehandhabt wird , und auf MSDN wurde eine Frage dazu beantwortet, ob eine Bereinigung erforderlich ist . Aber was ist, wenn es nie zweimal von derselben Sitzung ausgeführt wird?

Ich habe auch gehört, dass es einen Garbage Collection-Prozess im Hintergrund gibt, der diesen Speicherplatz freigibt, sobald die Tabelle außerhalb des Gültigkeitsbereichs liegt.

Das Abschneiden einer temporären Tabelle am Ende der gespeicherten Prozedur, die sie erstellt, scheint zu bewirken, dass der von der Tabelle in tempdb verwendete Speicherplatz für die Daten schneller freigegeben wird, als wenn trotz gegenteiliger Erwartungen keine abgeschnittene Anweisung verwendet wird. Warum?

Welche relativen Auswirkungen auf die Leistung hätte die Verwendung oder Nichtverwendung einer solchen abgeschnittenen Anweisung? Bei der Verwendung der SNAPSHOT-Isolation wird Tempdb häufig überlastet, und ich würde denken, dass das Freigeben des in Tempdb verwendeten Speicherplatzes aus einer großen Temp-Tabelle so schnell wie möglich ein ansonsten unnötiges Tempdb-Wachstum verhindern würde. Würde diese mögliche Platzersparnis zu Lasten der Leistung gehen?

Hier ist ein Code zum Reproduzieren des Problems (hauptsächlich von @TheGameiswar, mit einigen Änderungen):

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

Die kommentierten Zeilen wurden für einige Läufe auskommentiert und für andere nicht kommentiert. Als das TRUNCATEauskommentiert wurde, dauerte es zwischen 2,25 und 4,5 Sekunden, bis die Ergebnisse der tempdb.sys.dm_db_file_space_usageAbfrage (4472 weitere Seiten und 34,9375 MB größer) mit dem Ergebnis übereinstimmten, bevor die Prozedur ausgeführt wurde. Wenn die Zeilen (einschließlich der TRUNCATE) nicht kommentiert waren, dauerte es nur etwa 0,11 bis 0,9 Sekunden. Diese Ergebnisse stammen von einem Live-System mit geringfügigem Datenwachstum in der Quelltabelle während dieses Experiments.

Beispielausgabe mit auskommentiertem Code (2,69 Sekunden vom ersten bis zum letzten "endgültigen" Eintrag):

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

Beispielergebnisse mit unkommentiertem Code (0,11 Sekunden vom ersten bis zum letzten "endgültigen" Eintrag):

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
Mark Freeman
quelle

Antworten:

12

Das Abschneiden einer temporären Tabelle am Ende der gespeicherten Prozedur, die sie erstellt, scheint zu bewirken, dass der von der Tabelle in tempdb verwendete Speicherplatz für die Daten schneller freigegeben wird, als wenn trotz gegenteiliger Erwartungen keine abgeschnittene Anweisung verwendet wird. Warum?

Wenn die temporäre Tabelle groß genug ist ( mehr als 128 Speicherbereiche ), werden die physischen Seitenfreigaben aufgeschoben und von einer Hintergrundsystemaufgabe ausgeführt. Dies gilt unabhängig davon, ob ein expliziter TRUNCATE TABLEWert verwendet wird oder nicht.

Der einzige Unterschied ist ein winziges Implementierungsdetail. Ein expliziter TRUNCATE TABLEVorgang erstellt eine Aufgabe mit einem kürzeren Zeitgeber als die (ansonsten identische) verzögerte Löschaufgabe, die durch die temporäre Tabellenbereinigung erstellt wurde:

Call Stack, weil die Leute sie mögen

Ob dies zufällig oder beabsichtigt ist, kann niemand erraten. Dies kann sich natürlich jederzeit ändern, da dieser Detaillierungsgrad weit über die unterstützte Produktoberfläche hinausgeht.

Wenn Sie das verzögerte Löschen global mit einem (meistens) undokumentierten Ablaufverfolgungsflag deaktivieren:

DBCC TRACEON (671, -1);

... die Freigabe wird in beiden Fällen synchron durchgeführt, und Sie werden keinen Unterschied im Timing feststellen.

Welche relativen Auswirkungen auf die Leistung hätte die Verwendung oder Nichtverwendung einer solchen abgeschnittenen Anweisung? Bei der Verwendung der SNAPSHOT-Isolation wird Tempdb häufig überlastet, und ich würde denken, dass das Freigeben des in Tempdb verwendeten Speicherplatzes aus einer großen Temp-Tabelle so schnell wie möglich ein ansonsten unnötiges Tempdb-Wachstum verhindern würde. Würde diese mögliche Platzersparnis zu Lasten der Leistung gehen?

Ich bezweifle ernsthaft, dass dies jemals einen großen Unterschied machen würde. Wenn Größe von tempdb den höchsten Anforderungen Ihrer Workload entspricht, spielt es keine Rolle, ob ein verzögerter Abfall nach einer oder drei Sekunden auftritt. Die gleiche Arbeit wird erledigt; es ist nur ein kleiner Unterschied im Timing.

Auf der anderen Seite: Wenn Sie sich TRUNCATE TABLEam Ende Ihrer gespeicherten Prozeduren mit temporären Tabellen wohler fühlen , gehen Sie so vor. Ich bin mir keiner besonderen Nachteile bewusst.

Paul White 9
quelle