2010-03-25 87 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