This script returns the Duplicate indexes on any database (if any).
Compatible with SQL Server 2000 only.
Latest update Checks for possible duplications and removes them. Further, additional fields are displayed to support decision making.
This script returns the Duplicate indexes on any database (if any).
Compatible with SQL Server 2000 only.
Latest update Checks for possible duplications and removes them. Further, additional fields are displayed to support decision making.
/*
Find Duplicate Indexes
This script returns the Duplicate indexes on any database
I use 2 User defined Functions
Compatible with SQLServer 2000 (I used sp3)
It won't work in SQL Server 7.0 because It uses user-defined functions and a Memory.
Created by G.R. Preethiviraj Kulasingham
pkulasingham@virtusa.com
Written on : February 20, 2003
Modified on : May 18, 2004
Additional code written to remove duplicate entries.
Additional code to include index properties.
*/
IF EXISTS(Select id from sysobjects Where id = object_id('dbo.GetColID'))
DROP FUNCTION dbo.getColID
GO
Create Function dbo.getColID (@TableID int, @indid int)
/*
Parameters:
@TableID: ID of the Table
@IndID : ID of the Index
Returns All the Columns (ID) for the given index in string format seperated by '&'sign. '-' is added for descending keys
*/
Returns Varchar(200)
As
BEGIN
Declare @SQL varchar(200)
Set @SQL =''
Select @SQL= @SQL +'&'+ convert(varchar(7),((indexkey_property(id, indid, keyno, 'isdescending')*-2)+1)* colid) from sysindexkeys
Where id =@Tableid and indid=@Indid
Order by id, indid, Keyno
IF LEN(@SQL)>1
Select @SQL = @SQL +'&'
Return @SQL
END
GO
IF EXISTS(Select id from sysobjects Where id = object_id('dbo.GetColList'))
DROP FUNCTION dbo.getColList
GO
Create Function dbo.getColList (@Tableid int, @indid int)
/*
Parameters:
@TableID: ID of the Table
@IndID : ID of the Index
Returns Index Key (column names) for the given index in string format seperated by commas.
*/
Returns Varchar(8000)
As
BEGIN
Declare @SQL varchar(8000)
Set @SQL =''
Select @SQL= @SQL +', '+ INDEX_Col(User_name(ObjectProperty(@TableID, 'Ownerid'))+'.'+Object_name(@TableID), @indid, keyno)+
Case indexkey_property(id, indid, keyno, 'isdescending') When 1 Then '(Desc)' Else '' end from sysindexkeys
Where id =@Tableid and indid=@Indid
Order by id, indid, Keyno
IF LEN(@SQL)>2
Select @SQL = SUbString(@SQL, 3, LEN(@SQL)-2)
Return @SQL
END
GO
/*
@TempTable is used to store the keys in long string format
*/
Declare @TempTable Table (
ID int ,
Indid int,
ColID Varchar(200),
Status int
)
Declare @Duplicates Table (
LineID int Identity(1,1),
ID int ,
hasClustered char(3) not null default('NO'),
Indid1 int,
ColID1 Varchar(200),
Status1 int,
Desc1 varchar(200),
IndID2 int,
ColID2 Varchar(200),
Status2 int,
Desc2 varchar(100)
)
Insert into @TempTable
Select Id, indid, dbo.GetColid(id, indid), status from Sysindexes
where (status & 64)=0
order by id
Delete @TempTable Where ColID=''
Insert into @Duplicates (ID, IndID1, ColID1, Desc1, Status1, IndID2, ColID2, desc2, status2 )
Select A.ID, A.IndID, A.ColID, '', A.status, B.IndID, B.ColID, '', B.status
from @Temptable A, @TempTable B
Where A.id = b.id and a.indid<>b.indid and
a.colid like b.colid
+'%'
--This part removes the duplicate entries.
Delete @Duplicates Where LineID In (
Select A.LineID from @Duplicates A, @Duplicates B
Where A.ID = B.ID and A.IndID1= B.IndID2 and A.IndID2= B.IndID1 and A.LineID>B.LineID)
Delete @Duplicates Where LineID In (
Select A.LineID from @Duplicates A, @Duplicates B
Where A.ID = B.ID and A.IndID1 = B.IndID2 )
-- Identify the index properties
Update @Duplicates Set Desc1 =CASE status1 & 16 WHEN 0 THEN 'Nonclustered' ELSE 'Clustered' END
Update @Duplicates Set Desc2 =CASE status2 & 16 WHEN 0 THEN 'Nonclustered' ELSE 'Clustered' END
Declare @Desc varchar(20), @Number int
Declare spt_Vals Cursor
FOR
Select name, number from master.dbo.spt_Values
Where type ='I' and number in (1,2, 4, 32, 2048, 4096)
Order by number
Open spt_vals
FETCH Next from spt_vals into @Desc, @Number
WHILE @@FETCH_STATUS=0
BEGIN
Update @Duplicates Set Desc1 = Desc1 + ', '+ @Desc
where status1 & @number <>0
Update @Duplicates Set Desc2 = Desc2 + ', '+ @Desc
where status2 & @number <>0
FETCH Next from spt_vals into @Desc, @Number
END
CLOSE spt_Vals
DEALLOCATE spt_vals
Update @Duplicates Set Desc1 = replace(Desc1, 'unique, primary key', 'primary key'),
Desc2 = replace(Desc2, 'unique, primary key', 'primary key')
Update @Duplicates Set Desc1 = replace(Desc1, 'unique, unique key', 'unique key'),
Desc2 = replace(Desc2, 'unique, unique key', 'unique key')
-- Identify whether table has clustered index
Update @Duplicates Set HasClustered = 'YES' Where id in (
Select id From sysIndexes Where IndId=1)
--Update @Duplicates Set HasClustered = 'NO' Where id in (
--Select id From sysIndexes Where IndId=0)
Select User_name(ObjectProperty(A.ID, 'Ownerid'))+'.'+Object_name(a.id) 'Table Name', HasClustered,
IA.Name 'Index 1', dbo.GetColList(A.id, A.indid1) 'Keys of Index 1', A.Desc1 'Desc 1',
IB.Name 'Index 2', dbo.GetColList(A.id, A.indid2) 'Columns of Index 2', A.Desc2 'Desc 2'
from @Duplicates A, SysIndexes IA, Sysindexes IB
Where IA.id =A.id and IA.indId = A.IndID1 and IB.ID = A.ID and IB.indId=A.IndID2
order by User_name(ObjectProperty(A.ID, 'Ownerid'))+'.'+Object_name(a.id)
/*
GO
DROP FUNCTION dbo.getColList
GO
DROP FUNCTION dbo.getColID
GO
*/