Может ли кто-либо предоставить script для перестройки и повторной индексации фрагментированного индекса, когда "avg_fragmentation_in_percent" превышает определенные пределы (лучше, если курсор не используется)?
Script для восстановления и переиндексации фрагментированного индекса?
Ответ 1
Чтобы восстановить использование:
ALTER INDEX __NAME_OF_INDEX__ ON __NAME_OF_TABLE__ REBUILD
или для реорганизации использования:
ALTER INDEX __NAME_OF_INDEX__ ON __NAME_OF_TABLE__ REORGANIZE
Реорганизация должна использоваться при более низких (< 30%) фрагментах, но только восстановление (что тяжелее для базы данных) сокращает фрагментацию до 0%.
Для получения дополнительной информации см. https://msdn.microsoft.com/en-us/library/ms189858.aspx
Ответ 2
Два решения: один простой и еще один продвинутый.
Введение
Доступны два решения в зависимости от серьезности вашей проблемы.
Замените свои собственные значения следующим образом:
- Замените
XXXMYINDEXXXX
на имя индекса. - Замените
XXXMYTABLEXXX
именем таблицы. - Замените
XXXDATABASENAMEXXX
именем базы данных.
Решение 1. Индексирование
Восстановить все индексы для таблицы в автономном режиме
ALTER INDEX ALL ON XXXMYTABLEXXX REBUILD
Перестроить один указанный индекс для таблицы в автономном режиме
ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REBUILD
Решение 2. Фрагментация
Фрагментация - это проблема в таблицах, в которых регулярно добавляются и удаляются записи.
Проверить процент фрагментации
SELECT
ips.[index_id] ,
idx.[name] ,
ips.[avg_fragmentation_in_percent]
FROM
sys.dm_db_index_physical_stats(DB_ID(N'XXXMYDATABASEXXX'), OBJECT_ID(N'XXXMYTABLEXXX'), NULL, NULL, NULL) AS [ips]
INNER JOIN sys.indexes AS [idx] ON [ips].[object_id] = [idx].[object_id] AND [ips].[index_id] = [idx].[index_id]
Фрагментация 5..30%
Если значение фрагментации больше 5%, но менее 30%, то стоит реорганизовать индексы.
Реорганизовать все индексы для таблицы
ALTER INDEX ALL ON XXXMYTABLEXXX REORGANIZE
Реорганизовать один указанный индекс для таблицы
ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REORGANIZE
Фрагментация 30% +
Если значение фрагментации составляет 30% или больше, тогда стоит перестроить индексы в онлайн-режиме.
Перестроить все индексы в онлайн-режиме для таблицы
ALTER INDEX ALL ON XXXMYTABLEXXX REBUILD WITH (ONLINE = ON)
Перестроить один указанный индекс в онлайн-режиме для таблицы
ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REBUILD WITH (ONLINE = ON)
Ответ 3
Вот измененный скрипт, который я взял с http://www.foliotek.com/devblog/sql-server-optimization-with-index-rebuilding, который мне посчитал полезным опубликовать здесь. Хотя он использует курсор, и я знаю, в чем главная проблема с курсорами, его можно легко преобразовать в версию с курсором.
Он хорошо документирован, и вы можете легко прочитать его и изменить в соответствии с вашими потребностями.
IF OBJECT_ID('tempdb..#work_to_do') IS NOT NULL
DROP TABLE tempdb..#work_to_do
BEGIN TRY
--BEGIN TRAN
use yourdbname
-- Ensure a USE statement has been executed first.
SET NOCOUNT ON;
DECLARE @objectid INT;
DECLARE @indexid INT;
DECLARE @partitioncount BIGINT;
DECLARE @schemaname NVARCHAR(130);
DECLARE @objectname NVARCHAR(130);
DECLARE @indexname NVARCHAR(130);
DECLARE @partitionnum BIGINT;
DECLARE @partitions BIGINT;
DECLARE @frag FLOAT;
DECLARE @pagecount INT;
DECLARE @command NVARCHAR(4000);
DECLARE @page_count_minimum SMALLINT
SET @page_count_minimum = 50
DECLARE @fragmentation_minimum FLOAT
SET @fragmentation_minimum = 30.0
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
-- and convert object and index IDs to names.
SELECT object_id AS objectid ,
index_id AS indexid ,
partition_number AS partitionnum ,
avg_fragmentation_in_percent AS frag ,
page_count AS page_count
INTO #work_to_do
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL,
'LIMITED')
WHERE avg_fragmentation_in_percent > @fragmentation_minimum
AND index_id > 0
AND page_count > @page_count_minimum;
IF CURSOR_STATUS('global', 'partitions') >= -1
BEGIN
PRINT 'partitions CURSOR DELETED' ;
CLOSE partitions
DEALLOCATE partitions
END
-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR LOCAL
FOR
SELECT *
FROM #work_to_do;
-- Open the cursor.
OPEN partitions;
-- Loop through the partitions.
WHILE ( 1 = 1 )
BEGIN;
FETCH NEXT
FROM partitions
INTO @objectid, @indexid, @partitionnum, @frag, @pagecount;
IF @@FETCH_STATUS < 0
BREAK;
SELECT @objectname = QUOTENAME(o.name) ,
@schemaname = QUOTENAME(s.name)
FROM sys.objects AS o
JOIN sys.schemas AS s ON s.schema_id = o.schema_id
WHERE o.object_id = @objectid;
SELECT @indexname = QUOTENAME(name)
FROM sys.indexes
WHERE object_id = @objectid
AND index_id = @indexid;
SELECT @partitioncount = COUNT(*)
FROM sys.partitions
WHERE object_id = @objectid
AND index_id = @indexid;
SET @command = N'ALTER INDEX ' + @indexname + N' ON '
+ @schemaname + N'.' + @objectname + N' REBUILD';
IF @partitioncount > 1
SET @command = @command + N' PARTITION='
+ CAST(@partitionnum AS NVARCHAR(10));
EXEC (@command);
--print (@command); //uncomment for testing
PRINT N'Rebuilding index ' + @indexname + ' on table '
+ @objectname;
PRINT N' Fragmentation: ' + CAST(@frag AS VARCHAR(15));
PRINT N' Page Count: ' + CAST(@pagecount AS VARCHAR(15));
PRINT N' ';
END;
-- Close and deallocate the cursor.
CLOSE partitions;
DEALLOCATE partitions;
-- Drop the temporary table.
DROP TABLE #work_to_do;
--COMMIT TRAN
END TRY
BEGIN CATCH
--ROLLBACK TRAN
PRINT 'ERROR ENCOUNTERED:' + ERROR_MESSAGE()
END CATCH
Ответ 4
Я нашел, что script очень хорошо поддерживает индексы, вы можете запустить это по ночам или в любой другой таймфрейм, который вы пожелаете.
Ответ 5
Реальный ответ в 2016 и 2017 годах: Используйте сценарии Ola Hallengren:
https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html
Это все, что нам нужно знать или беспокоиться, на этом этапе нашей взаимной эволюции.
Ответ 6
Запрос для REBUILD/REORGANIZE индексов
- 30% <= перестроить
- 5% <= реорганизовать
- 5%> ничего не делать
Запрос:
SELECT OBJECT_NAME(ind.OBJECT_ID) AS TableName,
ind.name AS IndexName, indexstats.index_type_desc AS IndexType,
indexstats.avg_fragmentation_in_percent,
'ALTER INDEX ' + QUOTENAME(ind.name) + ' ON ' +QUOTENAME(object_name(ind.object_id)) +
CASE WHEN indexstats.avg_fragmentation_in_percent>30 THEN ' REBUILD '
WHEN indexstats.avg_fragmentation_in_percent>=5 THEN 'REORGANIZE'
ELSE NULL END as [SQLQuery] -- if <5 not required, so no query needed
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) indexstats
INNER JOIN sys.indexes ind ON ind.object_id = indexstats.object_id
AND ind.index_id = indexstats.index_id
WHERE
--indexstats.avg_fragmentation_in_percent , e.g. >10, you can specify any number in percent
ind.Name is not null
ORDER BY indexstats.avg_fragmentation_in_percent DESC
Выход
TableName IndexName IndexType avg_fragmentation_in_percent SQLQuery
--------------------------------------------------------------------------------------- ------------------------------------------------------
Table1 PK_Table1 CLUSTERED INDEX 75 ALTER INDEX [PK_Table1] ON [Table1] REBUILD
Table1 IX_Table1_col1_col2 NONCLUSTERED INDEX 66,6666666666667 ALTER INDEX [IX_Table1_col1_col2] ON [Table1] REBUILD
Table2 IX_Table2_ NONCLUSTERED INDEX 10 ALTER INDEX [IX_Table2_] ON [Table2] REORGANIZE
Table2 IX_Table2_ NONCLUSTERED INDEX 3 NULL