Я надеюсь, что кто-то может помочь мне с этим скриптом. Я хотел создать 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: если у вас есть другие предложения или обнаружили ошибку в скрипте - для улучшения кода, пожалуйста, дайте мне знать.
Привет Торстен, я уже моделируется DELETE #DatabaseList и «удаляет», что конкретное имя базы данных из списка, хотя, ваше предложение, безусловно, лучше. У меня такое чувство, что вычисление фрагментации индексов может быть проблемой, поскольку одна база данных имеет размер 50 ГБ и 505 таблиц, вероятно, между 1000-1500 индексами. – dovla091
На самом деле, пока я писал комментарий выше, расчет фрагментации закончен. Всего насчитывается 622 некластеризованных индекса. Это была проблема, или я должен сказать бутылочную шее. Для завершения потребовалось полные 32 минуты 55 секунд, только для одной базы данных. – dovla091
Еще один вопрос, я когда-то читал, что нецелесообразно перестраивать кластерные индексы, так как вы можете нарушить целостность базы данных. Я не уверен, правильно ли понимаю, каждая перестройка отбрасывает индекс и перестраивает его вместе с основным и внешним ключом. Это правда? – dovla091