How can I drop all indexes in a SQL database with one command?

Viewed 91096

So, how can I drop all indexes in a SQL database with one command? I have this command that will get me all the 20 or so drop statements, but how can I run all of those drop statements from this "result set"?

select * from vw_drop_idnex;

Another variation that gives me the same list is:

SELECT  'DROP INDEX ' + ix.Name + ' ON ' + OBJECT_NAME(ID)  AS QUERYLIST
FROM  sysindexes ix
WHERE   ix.Name IS NOT null and ix.Name like '%pre_%'

I tried to do "exec(select cmd from vw_drop_idnex)" and it didn't work. I am looking for something that works like a for loop and runs the queries one by one.

-----------------------

With Rob Farleys help, final draft of the script is:

declare @ltr nvarchar(1024);
SELECT @ltr = ( select 'alter table '+o.name+' drop constraint '+i.name+';'
  from sys.indexes i join sys.objects o on  i.object_id=o.object_id
  where o.type<>'S' and is_primary_key=1
  FOR xml path('') );
exec sp_executesql @ltr;

declare @qry nvarchar(1024);
select @qry = (select 'drop index '+o.name+'.'+i.name+';'
  from sys.indexes i join sys.objects o on  i.object_id=o.object_id
  where o.type<>'S' and is_primary_key<>1 and index_id>0
for xml path(''));
exec sp_executesql @qry
7 Answers

None of the answers quite suited my needs.

I needed one that will also drop indexes that backup unique or primary constraints (except if these can't be dropped as they back up a foreign key)

DECLARE @SqlScript NVARCHAR(MAX);


SELECT @SqlScript = 
(
SELECT 
'
BEGIN TRY
'+ CASE WHEN 1 IN (i.is_primary_key, i.is_unique_constraint) THEN
 '
 ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(i.object_id)) + '.' + QUOTENAME(t.name)  + ' DROP CONSTRAINT ' + QUOTENAME(i.name) + ';'
else
 '
 DROP INDEX ' + QUOTENAME(i.name)  + ' ON ' + QUOTENAME(OBJECT_SCHEMA_NAME(i.object_id)) + '.' + QUOTENAME(t.name)
 END+'

END TRY
BEGIN CATCH
RAISERROR(''Could not drop %s on table %s'', 0,1, ' + QUOTENAME(i.name, '''') + ', ' + QUOTENAME(t.name, '''') + ')
END CATCH
'
FROM sys.indexes i
JOIN sys.tables t ON i.object_id = t.object_id
WHERE i.type_desc IN ('CLUSTERED', 'NONCLUSTERED' )
ORDER BY t.object_id, i.index_id DESC
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)');

--Return script that will be run 
SELECT @SqlScript AS [processing-instruction(x)]
FOR XML PATH('');

EXEC (@SqlScript);

The "Final Draft" that OP posts as part of his question errors out if there are already zero indexes on any table in the DB. I needed to fix that.

Also, I wanted more control over the process than dropping all indexes on all tables, so I wrote the following stored proc to do it one table at a time:

CREATE PROCEDURE [dbo].[sp_DropAllIndexesOnTable]

@TableName varchar(1000)

AS
BEGIN
SET NOCOUNT ON;

   DECLARE @DropCommand1 nvarchar(4000)
   DECLARE @DropCommand2 nvarchar(4000)

--Create Temp Table to hold the names and table names of all Clustered Indexes
    SELECT o.name AS TableName, i.name AS IndexName
      INTO #AllClustered
      FROM sys.indexes i 
INNER JOIN sys.objects o ON i.object_id=o.object_id
     WHERE o.type <> 'S'
       AND is_primary_key = 1

--Create Temp Table to hold the names and table names of all NonClustered Indexes
    SELECT o.name AS TableName, i.name AS IndexName
      INTO #AllNonClustered
      FROM sys.indexes i 
INNER JOIN sys.objects o ON i.object_id=o.object_id
     WHERE o.type <> 'S'
       AND is_primary_key <> 1 
       AND index_id > 0

--Create DROP CONSTRAINT command for the Primary Key Constraint if there is one
    SELECT @DropCommand1 = ( SELECT 'ALTER TABLE dbo.['+ TableName +'] DROP CONSTRAINT ['+ IndexName +'];'
                               FROM #AllClustered
                              WHERE TableName = @TableName
                                FOR xml path('') ); 

--Create DROP INDEX command for the indexes on the table if there are any 
    SELECT @DropCommand2 = ( SELECT 'DROP INDEX [' + IndexName + '] ON dbo.['+ TableName +'];'
                               FROM #AllNonClustered
                              WHERE TableName = @TableName
                                FOR xml path('') );

        IF (@DropCommand1 IS NULL AND @DropCommand2 IS NULL) PRINT 'No action taken, zero indexes found on table ' + @TableName
        IF @DropCommand1 IS NOT NULL EXEC sp_executesql @DropCommand1
        IF @DropCommand2 IS NOT NULL EXEC sp_executesql @DropCommand2

DROP TABLE IF EXISTS #AllClustered
DROP TABLE IF EXISTS #AllNonClustered

END
GO

I cycle through the specific tables in my DB which I want to drop indexes on using a loop, and I drop the indexes by calling this proc with the table name, and recreate better ones right after. This way, only one table at a time has no indexes.

The reason I do this and the number of tables I do it on would make your head spin, but I definitely needed a proc like this!

SELECT  'DROP INDEX [' + IX.NAME + '] ON ' + OBJECT_NAME(IX.OBJECT_ID) + '; '
FROM  SYS.INDEXES IX
  JOIN SYS.OBJECTS O ON  IX.OBJECT_ID = O.OBJECT_ID
  INNER JOIN SYS.SCHEMAS S ON O.SCHEMA_ID = S.SCHEMA_ID
WHERE 
  IX.NAME IS NOT NULL 
  AND O.TYPE <> 'S' 
  AND IS_PRIMARY_KEY <> 1 
  AND INDEX_ID > 0
  AND S.NAME != 'SYS' AND S.NAME!= 'SYS' AND IS_UNIQUE_CONSTRAINT = 0

Modify conditions according to your needs

If u want to delete PK constraints, you will get this message if you try to drop index:

An explicit DROP INDEX is not allowed on index... It is being used for PRIMARY KEY constraint enforcement.

Then, use this...

SELECT 'ALTER TABLE [' + O.NAME + '] DROP CONSTRAINT  ' + IX.NAME + '; '
FROM  SYS.INDEXES IX
  JOIN SYS.OBJECTS O ON  IX.OBJECT_ID = O.OBJECT_ID
  INNER JOIN SYS.SCHEMAS S ON O.SCHEMA_ID = S.SCHEMA_ID
WHERE 
  IX.NAME IS NOT NULL 
  AND O.TYPE <> 'S' 
  AND INDEX_ID > 0
  AND S.NAME != 'SYS' AND S.NAME!= 'SYS'
Related