Disable all non-clustered indexes
Solution 1
You can build the queries into a select statement, like so:
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);
Chars 13 and 10 are the line-feed/carriage-returns, so you can check the output by replacing EXEC
with PRINT
, and it will be more readable.
Solution 2
Build a table variable with the indexes and table names. Use a loop to iterate over them, and execute a dynamic SQL statement for each of them.
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
Solution 3
Using a cursor to script things is more idiomatic than a temp table (and slightly briefer). To re-enable the indexes, replace DISABLE with 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
spender
I give my time here because I get so much more in return. Useful things I've written that might help you: blinq: a modern typescript reimplementation of linq-to-objects over iterable objects BkTree: a c# implementation of a Burkhard-Keller tree for indexing data in metric spaces. ComparerBuilder: A small c# library for easily creating complex IComparer<T> instances that compare multiple properties. See this answer for a rationale. ts-comparer-builder: A typescript library for creating complex "compareFunctions" for use with Array.sort. Very similar to ComparerBuilder above. ts-bin-heap: A typescript binary-heap implementation. Very handy for priority queues, which in-turn are very useful for search algorithms such as A*. Things I've written for other people: pShare client (see also) for Duality solutions: A cross-platform, blockchain and WebRTC based file-sharing platform, written with TypeScript, React and Redux, using electronjs.
Updated on January 30, 2020Comments
-
spender over 4 years
I select a number of non-clustered indexes from my database with the following:
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'
I'd like to run the following over each of the results:
ALTER INDEX indexName ON tableName DISABLE
How would I go about doing this? Is there a better way?
EDIT
I'm doing this for the purpose of truncating tables, then rebuilding with "ALTER INDEX bla ON table REBUILD". This needs to be automated, so dropping and rebuilding would be a somewhat higher maintenance activity I'd rather avoid. Is this a bad plan? I need a means of emptying tables with minimum overhead.
-
Philip Kelley about 14 yearsBut put it in some form of loop (cursor or temp table/WHILE construct), to process each index in turn
-
Daniel Quinlan about 14 yearsGood point, but is disabling non-clustered indexes so expensive that it would be necessary?
-
spender about 14 yearsThis only pulls the last result in the set. The declare should be DECLARE @sql AS VARCHAR(MAX)=''; and the select should start SELECT @sql = @sql+'ALTE... to concatenate all the results together. Otherwise, very nice. I'm going to try this now.
-
JNK over 13 yearsDisabling a non-clustered index keeps the definition and allows recreate/rebuild about 50% faster the dropping and creating.
-
Zack almost 10 yearsYou're missing the
CURSOR
keyword in line 1 I believe.DECLARE cur_indexes CURSOR FOR
-
TarasB about 9 yearsThis script is great. It's maybe a different versions of SQL Server. But
indexName
andtableName
do not work for me:Invalid column name 'indexName'
. So I usedsys.indexes.name
andsys.objects.name
. I'm using SQL 2012. -
Daniel Quinlan about 9 yearsThanks @TarasB, I wrote this in 2010 when I was working on a project in MS-SQL 2005. I don't have 2012 in front of me, but you might want to make sure
name
is unique and that the join will work. Maybe theobject_id
has been renamed toid
or something similar. -
jumxozizi almost 7 yearsPlease quote the object names before someone creates a table called "...drop database..." or something.
'ALTER INDEX ' + quotename(sys.indexes.name, '"') + ' ON ' + quotename(sys.objects.name, '"') + ' DISABLE;'
. -
Daniel Quinlan almost 7 years@Rubiksmomo, well yeah, but aren't you describing a scenario with a rogue db-admin? If someone can already create tables with malicious names, I doubt quoting will save you from the damage they can do.
-
jumxozizi almost 7 yearsYeah, I'm not too worried about the SQL injection. It's just a habit to always block it. It would however be nice if the script worked even when you have an object with some special characters (like space) in the name.