2015-08-20 5 views
0

Я надеюсь, что кто-то может помочь мне с этим скриптом. Я хотел создать SQL-скрипт для восстановления всех некластеризованных индексов с опцией «онлайн», чтобы предотвратить блокировку таблиц при восстановлении индексов, а также без использования курсора (который замедляет работу). По этой причине я использовал цикл While (по крайней мере, большинство разработчиков SQL), поэтому я написал SQL-скрипт. Что я заметил, SQL-скрипт выполняется навсегда. На одной тестовой машине я оставил ее в течение 12 минут, после чего я прервал операцию ...SQL-скрипт выполняется навсегда - возможный цикл?

Может ли какой-нибудь SQL-гуру рассказать мне, что вызывает бутылочную шее? Есть ли лучший способ сделать это, или, возможно, «тонкую настройку» текущего скрипта?

Образец старого кода:

USE MASTER 
GO 
DECLARE @DbName AS VARCHAR(50), 
    @DBIndexName AS VARCHAR(250), 
    @DBTableName AS VARCHAR(100), 
    @AlterCommand AS VARCHAR(500), 
    @SwitchDB AS NVARCHAR(50) 

SELECT name INTO #DatabaseList FROM master..sysdatabases 
WHILE EXISTS (SELECT * FROM #DatabaseList) 
BEGIN 
    SELECT TOP 1 @DbName = name FROM #DatabaseList 
    ORDER BY name ASC 

    SET @SwitchDB = 'USE '[email protected] 
    EXEC(@SwitchDB) 

    -- pronaći sve index-e koji imaju fragmentaciju veću od 10%, te staviti u tablicu 
    SELECT object_name(dt.object_id) Tablename,si.name 
    IndexName,dt.avg_fragmentation_in_percent AS 
    ExternalFragmentation,dt.avg_page_space_used_in_percent AS 
    InternalFragmentation 
    INTO #FragmIndex 
    FROM 
    (
     SELECT object_id,index_id,avg_fragmentation_in_percent,avg_page_space_used_in_percent 
     FROM sys.dm_db_index_physical_stats (db_id(@DbName),null,null,null,'DETAILED') 
     WHERE index_id <> 0 
    ) AS dt INNER JOIN sys.indexes si ON si.object_id=dt.object_id 
    AND si.index_id=dt.index_id AND dt.avg_fragmentation_in_percent>10 
    AND dt.avg_page_space_used_in_percent<75 and si.type_desc = 'NONCLUSTERED' ORDER BY avg_fragmentation_in_percent DESC 

    -- Napraviti petlju koja će izvršiti rebuild svih indexa 
    SET @SwitchDB = 'USE master' 
    EXEC (@SwitchDB) 

    WHILE EXISTS (SELECT * FROM #FragmIndex) 
    BEGIN 
     SELECT TOP 1 @DBIndexName = IndexName, @DBTableName = Tablename FROM #FragmIndex 
     ORDER BY IndexName ASC 

     -- rebuild index command setiranje na "ONLINE ON" kako bi se izbjeglo "zaključavanje tablice". 
     SET @AlterCommand ='ALTER INDEX '[email protected]+' ON '+ @DbName+'.dbo.'[email protected] +'REBUILD WITH (FILLFACTOR=80,STATISTICS_NORECOMPUTE = ON,ONLINE=ON)' 
     EXEC(@AlterCommand) 

     DELETE #FragmIndex 
     WHERE IndexName = @DBIndexName 
    END 

    DELETE #DatabaseList 
    WHERE name = @DbName 
END 
DROP TABLE #DatabaseList 
GO 

Большое спасибо и наилучшие пожелания.


Просто, чтобы добавить новый «исправленный код» - для всех вас, которые хотят использовать его, изменить его или что-то ... :)

USE MASTER 
GO 
DECLARE @DbName AS VARCHAR(50), 
    @DBIndexName AS VARCHAR(250), 
    @DBTableName AS VARCHAR(100), 
    @AlterCommand AS VARCHAR(500), 
    @SwitchDB AS NVARCHAR(50), 
    @numEntries AS BIGINT, 
    @numIndexEntries AS BIGINT 

SELECT name INTO #DatabaseList FROM master..sysdatabases 
SET @numEntries = (SELECT COUNT(*) FROM #DatabaseList) 

WHILE @numEntries > 0 --EXISTS (SELECT * FROM #DatabaseList) 
BEGIN 
    SELECT TOP 1 @DbName = name FROM #DatabaseList 
    ORDER BY name ASC 

    SET @SwitchDB = 'USE '[email protected] 
    EXEC(@SwitchDB) 

    -- pronaći sve index-e koji imaju fragmentaciju veću od 10%, te staviti u tablicu 
    SELECT object_name(dt.object_id) Tablename,si.name 
    IndexName,dt.avg_fragmentation_in_percent AS 
    ExternalFragmentation,dt.avg_page_space_used_in_percent AS 
    InternalFragmentation 
    INTO #FragmIndex 
    FROM 
    (
     SELECT object_id,index_id,avg_fragmentation_in_percent,avg_page_space_used_in_percent 
     FROM sys.dm_db_index_physical_stats (db_id(@DbName),null,null,null,'DETAILED') 
     WHERE index_id <> 0 
    ) AS dt INNER JOIN sys.indexes si ON si.object_id=dt.object_id 
    AND si.index_id=dt.index_id AND dt.avg_fragmentation_in_percent>10 
    AND dt.avg_page_space_used_in_percent<75 and si.type_desc = 'NONCLUSTERED' ORDER BY avg_fragmentation_in_percent DESC 

    -- Napraviti petlju koja će izvršiti rebuild svih indexa 
    SET @SwitchDB = 'USE master' 
    EXEC (@SwitchDB) 

    SET @numIndexEntries = (SELECT COUNT(*) FROM #FragmIndex) 
    WHILE @numIndexEntries > 0 --EXISTS (SELECT * FROM #FragmIndex) 
    BEGIN 
     SELECT TOP 1 @DBIndexName = IndexName, @DBTableName = Tablename FROM #FragmIndex 
     ORDER BY IndexName ASC 

     -- rebuild index command setiranje na "ONLINE ON" kako bi se izbjeglo "zaključavanje tablice". 
     SET @AlterCommand ='ALTER INDEX '[email protected]+' ON '+ @DbName+'.dbo.'[email protected] +'REBUILD WITH (FILLFACTOR=80,STATISTICS_NORECOMPUTE = ON,ONLINE=ON)' 
     EXEC(@AlterCommand) 

     DELETE #FragmIndex WHERE IndexName = @DBIndexName 
     SET @numIndexEntries = (SELECT COUNT(*) FROM #FragmIndex) 
    END 

    DELETE #DatabaseList WHERE name = @DbName 
    SET @numEntries = (SELECT COUNT(*) FROM #DatabaseList) 
END 
DROP TABLE #DatabaseList 
GO 

PS: если у вас есть другие предложения или обнаружили ошибку в скрипте - для улучшения кода, пожалуйста, дайте мне знать.

ответ

1

Возможны две возможные проблемы.

Прежде всего, заявление DELETE может не удалить ничего. Вы можете легко проверить это на PRINT с указанием количества записей в #DatabaseList после каждого заявления DELETE.

Во-вторых, EXISTS (SELECT * FROM #DatabaseList) может быть оценен один раз, а не на каждой итерации цикла.

Я бы изменить следующим образом:

... 

DECLARE @numEntries BIGINT 
SET @numEntries = (SELECT COUNT(*) FROM #DatabaseList) 

WHILE @numEntries > 0 
BEGIN 
    ... 

    DELETE #DatabaseList WHERE name = @DbName 
    SET @numEntries = (SELECT COUNT(*) FROM #DatabaseList) 
END 

... 
+0

Привет Торстен, я уже моделируется DELETE #DatabaseList и «удаляет», что конкретное имя базы данных из списка, хотя, ваше предложение, безусловно, лучше. У меня такое чувство, что вычисление фрагментации индексов может быть проблемой, поскольку одна база данных имеет размер 50 ГБ и 505 таблиц, вероятно, между 1000-1500 индексами. – dovla091

+0

На самом деле, пока я писал комментарий выше, расчет фрагментации закончен. Всего насчитывается 622 некластеризованных индекса. Это была проблема, или я должен сказать бутылочную шее. Для завершения потребовалось полные 32 минуты 55 секунд, только для одной базы данных. – dovla091

+0

Еще один вопрос, я когда-то читал, что нецелесообразно перестраивать кластерные индексы, так как вы можете нарушить целостность базы данных. Я не уверен, правильно ли понимаю, каждая перестройка отбрасывает индекс и перестраивает его вместе с основным и внешним ключом. Это правда? – dovla091

Смежные вопросы