SQL Server: Como acompanhar o progresso do comando CREATE INDEX?

36

SQL Server 2014, Ed Standard

Eu li que percent_complete em dm_exec_requests não funciona para CREATE INDEX e, na prática, percent_complete fica em 0. Portanto, isso não ajuda.

Atualmente, uso o método abaixo, que pelo menos me mostra movimento (que a criação do índice não está bloqueada). Mas não faço ideia se sou% 10 durante o processo ou% 99.

Tentei o método descrito aqui: https://dba.stackexchange.com/a/102545/6229, mas mostra um tempo de conclusão claramente errado (basicamente mostra 'now' para um processo de mais de 60 minutos em que estou a 10 minutos )

Como posso obter uma pista?

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 Restabelecer Monica
fonte

Respostas:

56

Eu acho que a consulta a seguir, pelo menos, chegará bem perto. Ele utiliza um DMV que foi introduzido no SQL Server 2014: sys.dm_exec_query_profiles (e obrigado a Martin Smith por me apresentar por meio deste DBA.StackExchange relacionado: Resposta da instrução SELECT INTO :-).

Observe:

  • !! Você precisará adicionar SET STATISTICS PROFILE ON;ou SET STATISTICS XML ON;no lote de consulta que está fazendo o CREATE INDEX(e colocado antes da CREATE INDEXinstrução, se isso não fosse óbvio); caso contrário, nenhuma linha será exibida nesta DMV para esse SPID / session_id !!

  • O INoperador é usado para filtrar a Index Insertlinha que, se incluída, aumentará os TotalRowsvalores, o que distorcerá os cálculos, pois essa linha nunca mostra nenhuma linha processada.

  • A contagem de linhas exibida aqui (ie TotalRows) é o dobro da contagem de linhas da tabela devido à operação de duas etapas, cada uma operando em todas as linhas: a primeira é uma "Verificação de tabela" ou "Verificação de índice em cluster" e a segunda é o tipo". Você verá "Verificação de tabela" ao criar um índice clusterizado ou criar um índice não clusterizado em um heap. Você verá "Verificação de índice em cluster" ao criar um índice não em cluster em um índice em cluster.

  • Esta consulta parece não funcionar ao criar índices filtrados. Por alguma razão, os índices filtrados a) não possuem a etapa "Classificar" eb) o row_countcampo nunca aumenta de 0.
    Não tenho certeza do que estava testando antes, mas agora meus testes indicam que os índices filtrados são capturados por esta consulta. Doce. Embora tenha apenas cuidado para que a contagem de linhas possa estar desativada (vou ver se consigo consertar isso algum dia).

  • Ao criar um índice clusterizado em um heap que já possui índices não clusterizados, os índices não clusterizados precisam ser reconstruídos (para trocar o RID - RowID - pela (s) chave (s) de índice clusterizado)) e cada reconstrução do índice não clusterizado ser uma operação separada e, portanto, não refletida nas estatísticas retornadas por esta consulta durante a criação do Índice de Cluster.

  • Esta consulta foi testada contra:

    • Criando:
      • Índices não agrupados em um heap
      • um índice agrupado (não existem índices não agrupados)
      • Índices não agrupados na tabela / índice agrupado
      • um índice agrupado quando já não existem índices agrupados
      • Índices não agrupados exclusivos na tabela / índice agrupado
    • Reconstrução (tabela com índice clusterizado e um índice não clusterizado; testado no SQL Server 2014, 2016, 2017 e 2019) via:
      • ALTER TABLE [schema_name].[table_name] REBUILD; (only Clustered Index shows up when using this method)
      • 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;

Saída de amostra:

                        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
fonte
Se você criar um índice não clusterizado em um heap e o novo índice tiver a mesma chave que um índice existente, a consulta utilizará um operador com physical_operator_nameset para N'Index Scan', em vez de N'Table Scan'ou N'Clustered Index Scan'. Além disso, será muito lento, pois executará várias pesquisas de RID.
Brian
Agora, se ao menos isso funcionasse em ALTER INDEX ALL ON dbo.table REBUILD ..... <g> #
Jonesome Reinstate Monica
11
BTW, isso também funciona bem para monitorar o progresso da implementação da compactação de página. sys.dm_exec_query_profiles é muito legal.
Todd Kleinhans
2
@JonesomeReinstateMonica Acabei de atualizar a consulta um pouco. Parece que de fato captura operações de reconstrução, tanto via ALTER INDEX ALLcomo mesmo (parcialmente) ALTER TABLE .. REBUILD. Por favor revise :-).
Solomon Rutzky 30/11
11
Oi @RoniVered Acabei de atualizar a consulta na resposta um pouco, para que ela capture as recriações de índice não clusterizado. Testei os dois tipos de comandos (embora não o DBCC, pensei nisso) e no SQL Server 2019, 2017, 2016 e 2014. Parece funcionar da mesma maneira em todos eles :-)
Solomon Rutzky