SQL Server: Wie verfolge ich den Fortschritt des Befehls CREATE INDEX?

36

SQL Server 2014, Std Ed

Ich habe gelesen, dass Percent_complete in dm_exec_requests nicht für CREATE INDEX funktioniert, und in der Praxis bleibt Percent_complete bei 0. Das hilft also nicht.

Ich verwende derzeit die unten stehende Methode, die mir zumindest die Bewegung anzeigt (dass die Indexerstellung nicht blockiert ist). Aber ich habe keine Ahnung, ob ich% 10 bin oder% 99.

Ich habe die hier beschriebene Methode ausprobiert: https://dba.stackexchange.com/a/102545/6229, aber sie zeigt eine eindeutig falsche Abschlusszeit (im Grunde zeigt sie "jetzt" für einen mehr als 60-minütigen Prozess an, in dem ich 10 Minuten bin) )

Wie kann ich einen Hinweis bekommen?

SELECT percent_complete, estimated_completion_time, reads, writes, logical_reads, text_size, *
FROM
sys.dm_exec_requests AS r
WHERE
r.session_id <> @@SPID
AND r.session_id = 58
Jonesome setzt Monica wieder ein
quelle

Antworten:

54

Ich denke, die folgende Abfrage wird Sie zumindest ganz nah bringen. Es wird eine DMV verwendet, die in SQL Server 2014 eingeführt wurde: sys.dm_exec_query_profiles (und danke an Martin Smith für die Einführung über diese verwandte DBA.StackExchange-Antwort: Fortschritt der SELECT INTO-Anweisung :-).

Bitte beachten Sie:

  • !! Sie müssen den Abfrage-Batch hinzufügen SET STATISTICS PROFILE ON;oder SET STATISTICS XML ON;in den Abfrage-Batch einfügen, der den Befehl ausführt CREATE INDEX(und vor die CREATE INDEXAnweisung gestellt wird, falls dies nicht offensichtlich ist). Andernfalls werden in dieser DMV keine Zeilen für diese SPID / !! angezeigt.session_id

  • Der INOperator wird verwendet, um die Index InsertZeile herauszufiltern, die , falls enthalten, die TotalRowsWerte erhöht , wodurch die Berechnungen verzerrt werden, da in dieser Zeile keine verarbeiteten Zeilen angezeigt werden.

  • Die hier angezeigte Zeilenzahl (dh TotalRows) ist doppelt so hoch wie die Zeilenzahl der Tabelle, da zwei Schritte ausgeführt werden, von denen jeder für alle Zeilen ausgeführt wird: der erste ist ein "Tabellenscan" oder "Clustered-Index-Scan" und der zweite ist die Art". Sie sehen "Table Scan", wenn Sie einen Clustered Index oder einen NonClustered Index auf einem Heap erstellen. Sie sehen "Clustered Index Scan", wenn Sie einen NonClustered Index für einen Clustered Index erstellen.

  • Diese Abfrage scheint beim Erstellen von gefilterten Indizes nicht zu funktionieren. Aus irgendeinem Grund haben gefilterte Indizes a) nicht den Schritt "Sortieren", und b) das row_countFeld steigt nie von 0 an.
    Nicht sicher , was ich zu testen , bevor, aber meine Tests nun zeigen , dass Filtered Indizes werden von dieser Abfrage erfasst. Süss. Beachten Sie jedoch, dass die Zeilenzählung möglicherweise deaktiviert ist (ich werde sehen, ob ich das eines Tages beheben kann).

  • Wenn Sie einen Clustered-Index auf einem Heap erstellen, auf dem sich bereits NonClustered-Indizes befinden, müssen die NonClustered-Indizes neu erstellt werden (um die RID (RowID) gegen die Clustered-Index-Schlüssel auszutauschen) eine separate Operation sein und sich daher nicht in den Statistiken widerspiegeln, die von dieser Abfrage während der Erstellung des Clustered Index zurückgegeben werden.

  • Diese Abfrage wurde getestet gegen:

    • Erstellen:
      • NonClustered-Indizes auf einem Heap
      • ein Clustered-Index (keine NonClustered-Indizes vorhanden)
      • NonClustered-Indizes für den Clustered-Index / die Clustered-Tabelle
      • ein Clustered-Index, wenn bereits NonClustered-Indizes vorhanden sind
      • Eindeutige NonClustered-Indizes für den Clustered-Index / die Clustered-Tabelle
    • Neuerstellung (Tabelle mit Clustered Index und einem NonClustered Index; getestet auf SQL Server 2014, 2016, 2017 und 2019) über:
      • ALTER TABLE [schema_name].[table_name] REBUILD;( Bei dieser Methode wird nur der Clustered Index angezeigt. )
      • ALTER INDEX ALL ON [schema_name].[table_name] REBUILD;
      • ALTER INDEX [index_name] ON [schema_name].[table_name] REBUILD;
DECLARE @SPID INT = 51;

;WITH agg AS
(
     SELECT SUM(qp.[row_count]) AS [RowsProcessed],
            SUM(qp.[estimate_row_count]) AS [TotalRows],
            MAX(qp.last_active_time) - MIN(qp.first_active_time) AS [ElapsedMS],
            MAX(IIF(qp.[close_time] = 0 AND qp.[first_row_time] > 0,
                    [physical_operator_name],
                    N'<Transition>')) AS [CurrentStep]
     FROM sys.dm_exec_query_profiles qp
     WHERE qp.[physical_operator_name] IN (N'Table Scan', N'Clustered Index Scan',
                                           N'Index Scan',  N'Sort')
     AND   qp.[session_id] = @SPID
), comp AS
(
     SELECT *,
            ([TotalRows] - [RowsProcessed]) AS [RowsLeft],
            ([ElapsedMS] / 1000.0) AS [ElapsedSeconds]
     FROM   agg
)
SELECT [CurrentStep],
       [TotalRows],
       [RowsProcessed],
       [RowsLeft],
       CONVERT(DECIMAL(5, 2),
               (([RowsProcessed] * 1.0) / [TotalRows]) * 100) AS [PercentComplete],
       [ElapsedSeconds],
       (([ElapsedSeconds] / [RowsProcessed]) * [RowsLeft]) AS [EstimatedSecondsLeft],
       DATEADD(SECOND,
               (([ElapsedSeconds] / [RowsProcessed]) * [RowsLeft]),
               GETDATE()) AS [EstimatedCompletionTime]
FROM   comp;

Beispielausgabe:

                        Rows                 Percent   Elapsed  Estimated    Estimated
CurrentStep  TotalRows  Processed  RowsLeft  Complete  Seconds  SecondsLeft  CompletionTime
-----------  ---------  ---------  --------  --------  -------  -----------  --------------
Clustered    11248640   4786937    6461703   42.56     4.89400  6.606223     2016-05-23
Index Scan                                                                   14:32:40.547
Solomon Rutzky
quelle
Wenn Sie einen nicht gruppierten Index auf einem Heap erstellen und der neue Index den gleichen Schlüssel wie ein vorhandener Index hat, verwendet die Abfrage einen Operator mit dem physical_operator_nameWert N'Index Scan', anstatt N'Table Scan'oder N'Clustered Index Scan'. Außerdem wird es sehr langsam sein, da es eine Reihe von RID-Suchen durchführen wird.
Brian
Wenn das nur bei ALTER INDEX ALL ON funktionieren würde, dann bei dbo.table REBUILD ..... <g>
Jonesome Reinstate Monica
1
Übrigens funktioniert dies auch gut, um den Fortschritt der Implementierung der Seitenkomprimierung zu überwachen. sys.dm_exec_query_profiles ist ziemlich cool.
Todd Kleinhans
Danke Solomon, das ist eine großartige Frage. Gibt es etwas Ähnliches wie das Verfolgen des Fortschritts eines ALTER INDEX - REBUILD-Befehls?
Roni Vered
1
@JonesomeReinstateMonica Ich habe gerade die Abfrage leicht aktualisiert. Es scheint, dass es tatsächlich Wiederherstellungsvorgänge erfasst, sowohl über ALTER INDEX ALLals auch (teilweise) ALTER TABLE .. REBUILD. Lesen Sie bitte :-).
Solomon Rutzky vor