Fortschritt der SELECT INTO-Anweisung


14

Unser ETL-Flow verfügt über eine langjährige SELECT INTO-Anweisung, mit der eine Tabelle im laufenden Betrieb erstellt und mit mehreren hundert Millionen Datensätzen gefüllt wird.

Die Aussage sieht ungefähr so ​​aus SELECT ... INTO DestTable FROM SrcTable

Zu Überwachungszwecken möchten wir uns einen ungefähren Überblick über den Fortschritt dieser Anweisung während der Ausführung verschaffen (ca. Zeilenanzahl, Anzahl der geschriebenen Bytes oder ähnliches).

Wir haben Folgendes erfolglos versucht:

-- Is blocked by the SELECT INTO statement:
select count(*) from DestTable with (nolock)

-- Returns 0, 0:
select rows, rowmodctr
from sysindexes with (nolock)
where id = object_id('DestTable')

-- Returns 0:
select rows
from sys.partitions
where object_id = object_id('DestTable')

Außerdem können wir die Transaktion in sehen sys.dm_tran_active_transactions, aber ich konnte keine Möglichkeit finden, die Anzahl der betroffenen Zeilen in einer gegebenen zu ermitteln transaction_id(etwas Ähnliches wie @@ROWCOUNTvielleicht, aber mit dem transaction_idArgument as).

Ich verstehe, dass auf SQL Server die SELECT INTO-Anweisung sowohl eine DDL- als auch eine DML-Anweisung in einer ist, und als solche wird die implizite Tabellenerstellung eine Sperroperation sein. Ich denke immer noch, dass es eine clevere Möglichkeit geben muss, eine Art Fortschrittsinformation zu erhalten, während die Anweisung ausgeführt wird.


Wenn Sie eine globale temporäre Tabelle ## TABLE verwendet haben, können Sie in der Indexspalte ## TABLE eine Auswahl mit Zählung durchführen, um die Anzahl der bereits geschriebenen Datensätze und die ungefähre Anzahl der insgesamt zu schreibenden Datensätze zu ermitteln.
CoveGeek

Antworten:


6

Ich vermute, dass rowsin sys.partitions0 ist, weil es noch nicht festgeschrieben wurde. Dies bedeutet jedoch nicht, dass SQL Server nicht weiß, was dort abläuft, wenn die Transaktion festgeschrieben wird. Der Schlüssel ist, sich daran zu erinnern, dass alle Operationen zuerst den Pufferpool (dh den Speicher) durchlaufen, unabhängig von COMMIT oder ROLLBACK der Operation. Daher können wir sys.dm_os_buffer_descriptorsnach diesen Informationen suchen :

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

SELECT  --OBJECT_NAME(sp.[object_id]) AS [TableName], sdobd.*, '---', sp.*, '---', sau.*
       SUM(sdobd.[row_count]) AS [BufferPoolRows],
       SUM(sp.[rows]) AS [AllocatedRows],
       COUNT(*) AS [DataPages]
FROM sys.dm_os_buffer_descriptors sdobd
INNER JOIN  sys.allocation_units sau
        ON sau.[allocation_unit_id] = sdobd.[allocation_unit_id]
INNER JOIN  sys.partitions sp
        ON  (   sau.[type] = 1
            AND sau.[container_id] = sp.[partition_id]) -- IN_ROW_DATA
        OR  (   sau.[type] = 2
            AND sau.[container_id] = sp.[hobt_id]) -- LOB_DATA
        OR  (   sau.[type] = 3
            AND sau.[container_id] = sp.[partition_id]) -- ROW_OVERFLOW_DATA
WHERE   sdobd.[database_id] = DB_ID()
AND     sdobd.[page_type] = N'DATA_PAGE'
AND     sp.[object_id] = (SELECT so.[object_id]
                          FROM   sys.objects so
                          WHERE  so.[name] = 'TestDump')

Wenn Sie die Details anzeigen möchten, kommentieren Sie die erste Zeile der Elemente in der Liste aus SELECT , kommentieren Sie Liste aus, und kommentieren Sie die verbleibenden 3 Zeilen aus.

Ich habe getestet, indem ich das Folgende in einer Sitzung ausgeführt und dann die obige Abfrage in einer anderen wiederholt ausgeführt habe.

SELECT so1.*
INTO   dbo.TestDump
FROM   sys.objects so1
CROSS JOIN sys.objects so2
CROSS JOIN sys.objects so3;

1
Das ist kreativ. Ich möchte nur eine Warnung hinzufügen, dass das Auflisten eines großen Pufferpools sehr langsam ist.
USR

1
Dies setzt voraus, dass noch keine Seiten aus dem Pufferpool entfernt wurden.
Martin Smith

@MartinSmith Können Seiten vor dem Festschreiben entfernt werden?
Solomon Rutzky

5
@srutzky - ja. Das Transaktionsprotokoll enthält alle Informationen, die zum Zurücksetzen erforderlich sind. Verschmutzte Seiten können auf Disc geschrieben werden - zB an einem Checkpoint oder vom Eager-Writer speziell in diesem Fall dann aus dem Buffer Pool entfernt.
Martin Smith

7

Zu Überwachungszwecken möchten wir uns einen ungefähren Überblick über den Fortschritt dieser Anweisung während der Ausführung verschaffen.

Einmalig oder laufend?

Wenn dies ein Bedarf ist, der im Voraus erwartet werden kann *, können Sie dies verwenden sys.dm_exec_query_profiles

Verbindung 1 (Sitzung 55)

SET STATISTICS XML ON

SELECT so1.*
INTO   dbo.TestDump
FROM   sys.all_objects so1
CROSS JOIN sys.all_objects so2
CROSS JOIN sys.all_objects so3
CROSS JOIN sys.all_objects so4
CROSS JOIN sys.all_objects so5;

Anschluss 2

select row_count
from sys.dm_exec_query_profiles
WHERE physical_operator_name = 'Table Insert' 
    AND session_id = 55;

Sie müssen möglicherweise zurück die Zeilen zählt summieren , wenn die SELECT INTOist Parallelität mit .

* Die Sitzung, die Sie mit dieser DMV überwachen möchten, muss für die Statistikerfassung mit SET STATISTICS PROFILE ONoder aktiviert sein SET STATISTICS XML ON. Das Anfordern eines "tatsächlichen" Ausführungsplans von SSMS funktioniert ebenfalls (da die letztere Option festgelegt ist).


Ich habe anscheinend vergessen, dies im Februar zu ändern, aber ich habe es nicht ganz vergessen :). Ich habe es gerade für diese verwandte Frage verwendet, da dieses OP mindestens im Jahr 2014 vorliegt : dba.stackexchange.com/questions/139191/… Vielen Dank, dass Sie darauf hingewiesen haben. Es ist ziemlich praktisch, DMV :-)
Solomon Rutzky

2
@ Srutzky yep es ist sehr nützlich. Und in den SSMS 2016 Live-Ausführungsplänen verwendet msdn.microsoft.com/en-gb/library/dn831878.aspx
Martin Smith

5

Ich glaube nicht, dass es eine Möglichkeit gibt, Zeilenzahlen zu ermitteln, aber Sie können die Menge der geschriebenen Daten schätzen, indem Sie Folgendes betrachten:

SELECT writes 
  FROM sys.dm_exec_requests WHERE session_id = <x>;

SELECT COUNT(*) FROM sys.dm_db_database_page_allocations
(<dbid>, OBJECT_ID(N'dbo.newtablename'), 0, NULL, 'LIMITED');

Wenn Sie eine Vorstellung davon haben, wie viele Seiten der Heapspeicher nach Abschluss aufnehmen soll, sollten Sie in der Lage sein,% complete zu berechnen. Die letztere Abfrage wird nicht schnell sein, wenn die Tabelle größer wird. Und wahrscheinlich am sichersten, READ UNCOMMITTEDwenn Sie die oben genannten Optionen verwenden (und das empfehle ich nicht oft für alles).


4

Wenn du das INSERTvon einem ändern könntest

SELECT ... INTO DestTable FROM SrcTable

zu einer

INSERT DestTable SELECT ... FROM SrcTable

dann würde deine select count(*) from DestTable with (nolock)Abfrage funktionieren.

Wenn dies nicht möglich ist, können Sie sp_WhoIsActive verwenden (oder in die DMVs eintauchen), um zu überwachen, wie viele Schreibvorgänge die Abfrage ausführt. Dies wäre eine ziemlich grobe Messgröße, könnte aber nützlich sein, wenn Sie die Anzahl der Schreibvorgänge zugrunde legen, die normalerweise ausgeführt werden.

Sie sollten in der Lage sein, minimale Protokollierung mit dem INSERToben genannten zu erhalten, wenn Sie hinzufügen WITH (TABLOCK).


Vielen Dank für diesen Kommentar. Wir wollen minimale Protokollierung, weshalb wir den SELECT ... INTO-Ansatz verwenden (und auch, weil wir faul sind ...)
Dan

1
Sie sollten in der Lage sein, minimale Protokollierung mit den INSERToben genannten zu erhalten, wenn Sie hinzufügenWITH(TABLOCK)
James Anderson

@JamesAnderson - Wenn die Tabelle als Heap belassen wird, wird sie nur erneut blockiert, da sie eine BULK_OPERATIONSperre einnimmt .
Martin Smith
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.