Отключить все некластеризованные индексы

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

SELECT  sys.objects.name tableName,
        sys.indexes.name indexName
FROM    sys.indexes
        JOIN sys.objects ON sys.indexes.object_id = sys.objects.object_id
WHERE   sys.indexes.type_desc = 'NONCLUSTERED'
        AND sys.objects.type_desc = 'USER_TABLE'

Я хотел бы запустить следующее по каждому из результатов:

ALTER INDEX indexName ON tableName DISABLE

Как мне это сделать? Есть ли лучший способ?

ИЗМЕНИТЬ

Я делаю это с целью усечения таблиц, а затем перестраиваю с помощью "ALTER INDEX bla ON table REBUILD". Это должно быть автоматизировано, поэтому отбрасывание и перестройка будут несколько более высокой эксплуатационной активностью, которую я бы предпочел избежать. Это плохой план? Мне нужно средство для опорожнения таблиц с минимальными накладными расходами.

Ответы

Ответ 1

Вы можете создавать запросы в оператор select, например:

DECLARE @sql AS VARCHAR(MAX)='';

SELECT @sql = @sql + 
'ALTER INDEX ' + sys.indexes.name + ' ON  ' + sys.objects.name + ' DISABLE;' +CHAR(13)+CHAR(10)
FROM 
    sys.indexes
JOIN 
    sys.objects 
    ON sys.indexes.object_id = sys.objects.object_id
WHERE sys.indexes.type_desc = 'NONCLUSTERED'
  AND sys.objects.type_desc = 'USER_TABLE';

EXEC(@sql);

Чарки 13 и 10 - это переводы строк/кареток, поэтому вы можете проверить вывод, заменив EXEC на PRINT, и это будет более читаемым.

Ответ 2

Создайте переменную таблицы с индексами и именами таблиц. Используйте цикл для итерации по ним и выполните динамический оператор SQL для каждого из них.

declare @Indexes table
(
    Num       int identity(1,1) primary key clustered,
    TableName nvarchar(255),
    IndexName nvarchar(255)
)

INSERT INTO @Indexes
(
    TableName,
    IndexName
)
SELECT  sys.objects.name tableName,
        sys.indexes.name indexName
FROM    sys.indexes
        JOIN sys.objects ON sys.indexes.object_id = sys.objects.object_id
WHERE   sys.indexes.type_desc = 'NONCLUSTERED'
        AND sys.objects.type_desc = 'USER_TABLE'

DECLARE @Max INT
SET @Max = @@ROWCOUNT

SELECT @Max as 'max'
SELECT * FROM @Indexes

DECLARE @I INT
SET @I = 1

DECLARE @TblName NVARCHAR(255), @IdxName NVARCHAR(255)

DECLARE @SQL NVARCHAR(MAX)

WHILE @I <= @Max
BEGIN
    SELECT @TblName = TableName, @IdxName = IndexName FROM @Indexes WHERE Num = @I
    SELECT @SQL = N'ALTER INDEX ' + @IdxName + N' ON ' + @TblName + ' DISABLE;'

    EXEC sp_sqlexec @SQL    

    SET @I = @I + 1

END

Ответ 3

OTOH, возможно, лучше DROP, а не DISABLE (или это небольшая синтаксическая разница между Oracle и MS SQL?). Причина, по которой я упоминаю, это то, что я помню таблицы, которые были засекречены, а excplicilty денормализованы два раза в день и мы были DROP-ing всех индексов, чтобы заставить DB перестроить как индексы, так и планы выполнения sproc после загрузки новой даты и восстановления всех индексов.

Конечно, для этого у нас был отдельный script, так как после его удаления индексы больше не входят в системные таблицы.

Ответ 4

Использование курсора для script вещей более идиоматично, чем временная таблица (и немного более короткая). Чтобы снова включить индексы, замените DISABLE на REBUILD.

DECLARE cur_indexes CURSOR FOR
SELECT  sys.objects.name tableName,
        sys.indexes.name indexName
FROM    sys.indexes
        JOIN sys.objects ON sys.indexes.object_id = sys.objects.object_id
WHERE   sys.indexes.type_desc = 'NONCLUSTERED'
        AND sys.objects.type_desc = 'USER_TABLE'

DECLARE @TblName NVARCHAR(255), @IdxName NVARCHAR(255)

DECLARE @SQL NVARCHAR(MAX)

open cur_indexes
fetch next from cur_indexes into @TblName, @IdxName

WHILE @@FETCH_STATUS = 0
BEGIN
    SELECT @SQL = N'ALTER INDEX ' + @IdxName + N' ON ' + @TblName + ' DISABLE;'

    EXEC sp_sqlexec @SQL    

    fetch next from cur_indexes into @TblName, @IdxName
END

close cur_indexes
deallocate cur_indexes