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 INDEX
declaración, si eso no fuera obvio), de lo contrario, no se mostrarán filas en este DMV para ese SPID / session_id
!!
El IN
operador se utiliza para filtrar la Index Insert
fila que, si se incluye, aumentará los TotalRows
valores, 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, TotalRows
es 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_count
campo 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
physical_operator_name
set enN'Index Scan'
, en lugar deN'Table Scan'
oN'Clustered Index Scan'
. Además, será muy lento, ya que realizará un montón de búsquedas RID.ALTER INDEX ALL
como incluso (parcialmente)ALTER TABLE .. REBUILD
. Por favor revise :-).