SQL Server: ¿Cómo rastrear el progreso del comando CREATE INDEX?

36

SQL Server 2014, Std Ed

He leído que percent_complete en dm_exec_requests no funciona para CREATE INDEX, y en la práctica, percent_complete se queda en 0. Así que eso no ayuda.

Actualmente uso el siguiente método, que al menos me muestra movimiento (que la creación del índice no está bloqueada). Pero no tengo idea si estoy% 10 a través del proceso o% 99.

Probé el método descrito aquí: /dba//a/102545/6229 pero muestra un tiempo de finalización de prueba claramente incorrecto (básicamente muestra 'ahora' para un proceso de más de 60 minutos en el que estoy en 10 minutos )

¿Cómo puedo obtener una 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 restablecer monica
fuente

Respuestas:

56

Creo que la siguiente consulta al menos te acercará bastante. Utiliza un DMV que se introdujo en SQL Server 2014: sys.dm_exec_query_profiles (y gracias a Martin Smith por presentármelo a través de este DBA relacionado. Respuesta de StackExchange: progreso de la instrucción SELECT INTO :-).

Tenga en cuenta:

  • !! ¡Necesitará agregar SET STATISTICS PROFILE ON;o SET STATISTICS XML ON;en el lote de consulta que está haciendo el CREATE INDEX(y colocado antes de la CREATE INDEXdeclaración, si eso no fuera obvio), de lo contrario, no se mostrarán filas en este DMV para ese SPID / session_id !!

  • El INoperador se utiliza para filtrar la Index Insertfila que, si se incluye, aumentará los TotalRowsvalores, lo que sesgará los cálculos ya que esa fila nunca muestra ninguna fila procesada.

  • El recuento de filas que se muestra aquí (es decir, TotalRowses el doble del recuento de filas de la tabla debido a que la operación toma dos pasos, cada uno opera en todas las filas: primero es un "Análisis de tabla" o "Análisis de índice agrupado", y el segundo es el "Ordenar". Verá "Escaneo de tabla" al crear un índice agrupado o al crear un índice no agrupado en un montón. Verá "Escaneo de índice agrupado" al crear un índice no agrupado en un índice agrupado.

  • Esta consulta no parece funcionar al crear índices filtrados. Por alguna razón, los Índices filtrados a) no tienen el paso "Ordenar", yb) el row_countcampo nunca aumenta de 0.
    No estoy seguro de lo que estaba probando antes, pero mis pruebas ahora indican que los índices filtrados son capturados por esta consulta. Dulce. Aunque solo tenga en cuenta que los recuentos de filas pueden estar desactivados (veré si puedo arreglar eso algún día).

  • Al crear un índice agrupado en un montón que ya tiene índices no agrupados, los índices no agrupados deben reconstruirse (para intercambiar el RID - RowID - por las claves de índice agrupadas), y cada reconstrucción del índice no agrupado se reconstruirá. ser una operación separada y, por lo tanto, no reflejarse en las estadísticas devueltas por esta consulta durante la creación del índice agrupado.

  • Esta consulta ha sido probada contra:

    • Creando:
      • Índices no agrupados en un montón
      • un índice agrupado (no existen índices no agrupados)
      • Índices no agrupados en el índice / tabla agrupados
      • un índice agrupado cuando los índices no agrupados ya existen
      • Índices únicos no agrupados en el índice / tabla agrupados
    • Reconstrucción (tabla con índice agrupado y un índice no agrupado; probado en SQL Server 2014, 2016, 2017 y 2019) a través de:
      • ALTER TABLE [schema_name].[table_name] REBUILD;( solo se muestra el índice agrupado cuando se usa este método )
      • 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;

Salida de muestra:

                        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
fuente
Si crea un índice no agrupado en un montón y el nuevo índice tiene la misma clave que un índice existente, la consulta utilizará un operador con physical_operator_nameset en N'Index Scan', en lugar de N'Table Scan'o N'Clustered Index Scan'. Además, será muy lento, ya que realizará un montón de búsquedas RID.
Brian
Ahora, si solo eso funcionara en ALTER INDEX ALL ON dbo.table REBUILD ..... <g>
Jonesome Reinstate Monica
1
Por cierto, esto también funciona bien para monitorear el progreso de la implementación de la compresión de la página también. sys.dm_exec_query_profiles es bastante genial.
Todd Kleinhans
2
@JonesomeReinstateMonica Acabo de actualizar la consulta ligeramente. Parece que efectivamente captura las operaciones de reconstrucción, tanto a través ALTER INDEX ALLcomo incluso (parcialmente) ALTER TABLE .. REBUILD. Por favor revise :-).
Solomon Rutzky
1
Hola @RoniVered Acabo de actualizar la consulta en la respuesta ligeramente para que capture las reconstrucciones de índice no en clúster. Probé ambos tipos de comandos (aunque no DBCC, solo pensé en eso), y en SQL Server 2019, 2017, 2016 y 2014. Parece que funciona igual en todos ellos :-)
Solomon Rutzky