SQL Server: как отслеживать ход выполнения команды CREATE INDEX?


36

SQL Server 2014, стандартный выпуск

Я читал, что процент_компонента в dm_exec_requests не работает для CREATE INDEX, и на практике, процент_компонента остается на 0. Так что это не помогает.

В настоящее время я использую метод ниже, который по крайней мере показывает мне движение (что создание индекса не заблокировано). Но я понятия не имею, нахожусь ли я% 10 в процессе или% 99.

Я попробовал метод, описанный здесь: /dba//a/102545/6229, но он показывает явно неправильное время завершения EST (он в основном показывает «сейчас» для 60 + минутного процесса, который я 10 минут в )

Как я могу получить подсказку?

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

Ответы:


56

Я думаю, что следующий запрос по крайней мере приблизит вас. Он использует DMV, который был представлен в SQL Server 2014: sys.dm_exec_query_profiles (и спасибо Мартину Смиту за представление его мне через этот связанный DBA.StackExchange Ответ: Ход выполнения инструкции SELECT INTO :-).

Пожалуйста, обратите внимание:

  • !! Вам нужно будет добавить SET STATISTICS PROFILE ON;или SET STATISTICS XML ON;в пакете запроса , который делает CREATE INDEX(и помещен перед тем в CREATE INDEXзаявлении, если это не было очевидно), еще ни одна строка не будет отображаться в этом DMV для этого ИСП / session_id !!

  • INОператор используется , чтобы отфильтровать Index Insertстроки , что, если он включен, приведет к увеличению TotalRowsзначения, которые будут искажать расчеты , так как эта строка никогда не показывает каких - либо обработанных строк.

  • Отображаемое здесь количество строк (то есть TotalRows) является двойным числом строк таблицы из-за операции, выполняемой в два этапа, каждый из которых работает со всеми строками: первый - «Сканирование таблицы» или «Сканирование кластерного индекса», а второй - «Сортировка». Вы увидите «Сканирование таблицы» при создании кластеризованного индекса или некластеризованного индекса в куче. Вы увидите «Сканирование кластеризованного индекса» при создании некластерного индекса в кластерном индексе.

  • Этот запрос не работает при создании отфильтрованных индексов. По какой-то причине отфильтрованные индексы а) не имеют шага «Сортировка», и б) row_countполе никогда не увеличивается с 0.
    Не уверен , что я испытывал раньше, но мои тесты теперь указывают , что отфильтрованных индексов будут захвачены этим запросом. Милая. Хотя остерегайтесь того, что число строк может быть выключено (я посмотрю, смогу ли я когда-нибудь это исправить).

  • При создании кластерного индекса в куче, в которой уже есть некластеризованные индексы, необходимо перестроить некластеризованные индексы (чтобы поменять RID - RowID - для ключа (ключей) кластерного индекса), и каждая перестройка некластерного индекса будет быть отдельной операцией и, следовательно, не отражаться в статистике, возвращаемой этим запросом при создании кластерного индекса.

  • Этот запрос был проверен на:

    • Создание:
      • Некластеризованные индексы в куче
      • кластеризованный индекс (некластеризованных индексов не существует)
      • Некластерные индексы в кластерном индексе / таблице
      • кластерный индекс, когда некластерные индексы уже существуют
      • Уникальные некластеризованные индексы в кластерном индексе / таблице
    • Перестройка (таблица с кластеризованным индексом и одним некластеризованным индексом; протестирована на SQL Server 2014, 2016, 2017 и 2019) с помощью:
      • ALTER TABLE [schema_name].[table_name] REBUILD;( при использовании этого метода отображается только кластерный индекс )
      • 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;

Образец вывода:

                        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установленным на N'Index Scan', а не N'Table Scan'или N'Clustered Index Scan'. Кроме того, он будет очень медленным, так как он выполнит несколько поисков RID.
Брайан

Теперь, если бы только это работало над ALTER INDEX ALL ON dbo.table REBUILD ..... <g>
Jonesome Reinstate Monica

1
Кстати, это также хорошо работает для отслеживания прогресса в реализации сжатия страниц. sys.dm_exec_query_profiles - это круто.
Тодд Кляйнханс

2
@JonesomeReinstateMonica Я только немного обновил запрос. Кажется, что он действительно захватывает операции восстановления, как через, так ALTER INDEX ALLи даже (частично) ALTER TABLE .. REBUILD. Пожалуйста ознакомтесь :-).
Соломон Руцкий

1
Привет @ RoniVered Я просто немного обновил запрос в ответе, чтобы он перехватывал пересчеты NonClustered Index. Я протестировал оба типа команд (хотя не DBCC, я только что подумал об этом) и на SQL Server 2019, 2017, 2016 и 2014. Кажется, что они работают одинаково для всех из них :-)
Соломон Руцки
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.