2010-03-25 114 views
14

我選擇了一些非聚集索引的從我的數據庫具有以下內容:禁用所有非聚集索引

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 ON BLA表重建」。這需要實現自動化,因此丟棄和重建將是我寧願避免的稍高的維護活動。這是一個糟糕的計劃嗎?我需要一種以最小開銷清空表格的方法。

+1

您可能會更好只是刪除它們,因爲沒有ALTER INDEX ENABLE,他們將需要重新創建。如果停用,它們將不會被維護。 – 2010-03-25 18:13:57

+2

如果丟失,則會丟失定義,並且如果(何時)需要重新創建它們,則必須記住它們。如果禁用,定義將會保留在系統表中,您不必擔心從頭開始重新創建它們。 – 2010-03-25 23:15:01

+2

@jl您可以使用ALTER INDEX REBUILD重新啓用索引。 – kristianp 2014-03-20 01:18:40

回答

24

您可以建立查詢到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是換行/回車符號,這樣你就可以用PRINT更換EXEC檢查輸出,它會更具可讀性。

+0

但是把它放在某種形式的循環中(遊標或臨時表/ WHILE構造),依次處理每個索引 – 2010-03-25 18:14:20

+0

好點,但禁用非聚簇索引太昂貴以至於有必要? – 2010-03-25 18:27:50

+1

這隻會拉取集合中的最後一個結果。聲明應該是DECLARE @sql AS VARCHAR(MAX)=''; select應該啓動SELECT @sql = @ sql +'ALTE ...將所有結果連接在一起。否則,非常好。我現在要試試這個。 – spender 2010-03-25 18:28:20

3

用索引和表名建立一個表變量。使用循環遍歷它們,併爲它們中的每一個執行動態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 
0

OTOH它可能會更好DROP寧可DISABLE(或者是Oracle和MS SQL?之間的小律語法差異:-)我提到的原因是,我記得是再增殖和excplicilty非規範化表每天兩次,我們刪除所有索引,以便在我們加載新日期並重建所有索引後強制DB重建索引和sproc執行計劃。

當然,我們有單獨的腳本,因爲一旦你放下它們,索引就不再在系統表中了。

+0

禁用非聚集索引可以保持定義,並且允許重新創建/重建的速度比創建和刪除快大約50%。 – JNK 2010-11-30 14:40:14

0

使用遊標來編寫腳本比使用臨時表(稍微簡單些)更具慣用性。要重新啓用索引,請用REBUILD替換DISABLE。

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 
+0

你錯過了我相信第1行的'CURSOR'關鍵字。 'DECLARE cur_indexes CURSOR FOR' – Zack 2014-06-19 15:58:32

+0

已更新,謝謝@Zack – kristianp 2014-06-21 01:51:22