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 s
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'
this worked for me we skip sys indexes and for constraints
declare @qry nvarchar(max);
select @qry = (
select 'IF EXISTS(SELECT * FROM sys.indexes WHERE name='''+ i.name +''' AND object_id = OBJECT_ID(''['+s.name+'].['+o.name+']'')) drop index ['+i.name+'] ON ['+s.name+'].['+o.name+']; '
from sys.indexes i
inner join sys.objects o on i.object_id=o.object_id
inner join sys.schemas s on o.schema_id = s.schema_id
where 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
for xml path(''));
exec sp_executesql @qry
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);
You're very close.
declare @qry nvarchar(max);
select @qry =
(SELECT 'DROP INDEX [' + ix.name + '] ON ' + OBJECT_NAME(ID) + '; '
FROM sysindexes ix
WHERE ix.Name IS NOT null and ix.Name like '%prefix_%'
for xml path(''));
exec sp_executesql @qry
Minor improvements to the accepted answer that I had to make in my own case, mostly to account for schemas:
declare @qry nvarchar(4000);
select @qry = (select 'drop index ['+s.name+'].['+o.name+'].['+i.name+'];'
from sys.indexes i join sys.objects o on i.object_id=o.object_id join sys.schemas s on o.schema_id=s.schema_id
where o.type<>'S' and is_primary_key<>1 and index_id>0 and s.name<>'sys'
for xml path(''));
exec sp_executesql @qry
Also: In my case it couldn't run in one go because the script becomes longer than 4000 characters. The only way I could think of to deal with that was to put a "top 20" on the inner select and execute it multiple times.
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!