Skip to content
Permalink
main
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
/*
sp_SQL2000_helpindex.sql
https://bornsql.ca/s/script-duplicate-index-finder/
Copyright (c) BornSQL.ca
Written by Randolph West, released under the MIT License
Last updated: 19 June 2020
Based on sp_helpindex from SQL Server 2000, this script outputs
an index structure in the same format as the 2005+ script by
Kimberly Tripp. This is written specifically for SQL Server 2000.
This script is called by sp_SQL2000_finddupes
See: https://www.sqlskills.com/blogs/kimberly/removing-duplicate-indexes/
-- June 2020: Renamed files, fixed formatting, and improved comments.
-- September 2013: Moved to GitHub.
-- May 2013: Worked around RID / UNIQUIFIER not displaying correctly.
-- August 2012: Updated copyright bits, cleaned up formatting and
-- comments.
-- March 2012: Based on SQL Server 2000 sp_helpindex with revised
-- code for columns in index levels.
*/
USE master
GO
IF OBJECTPROPERTY(OBJECT_ID('sp_SQL2000_helpindex'), 'IsProcedure') = 1
DROP PROCEDURE sp_SQL2000_helpindex
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_SQL2000_helpindex] @objname NVARCHAR(776) -- the table to check for indexes
AS
BEGIN
-- PRELIM
SET NOCOUNT ON
DECLARE @objid INT, -- the object id of the table
@indid SMALLINT, -- the index id of an index
@groupid SMALLINT, -- the filegroup id of an index
@indname sysname,
@groupname sysname,
@status INT,
@keys NVARCHAR(2126), --Length (16*max_identifierLength)+(15*2)+(16*3)
@dbname sysname
-- Check to see that the object names are local to the current database.
SELECT @dbname = PARSENAME(@objname, 3)
IF @dbname IS NOT NULL
AND @dbname <> DB_NAME()
BEGIN
RAISERROR(15250, -1, -1)
RETURN (1)
END
-- Check to see the the table exists and initialize @objid.
SELECT @objid = OBJECT_ID(@objname)
IF @objid IS NULL
BEGIN
SELECT @dbname = DB_NAME()
RAISERROR(15009, -1, -1, @objname, @dbname)
RETURN (1)
END
-- OPEN CURSOR OVER INDEXES (skip stats: bug shiloh_51196)
DECLARE ms_crs_ind CURSOR LOCAL STATIC FOR
SELECT [indid],
[groupid],
QUOTENAME(name, N']'),
[status]
FROM sysindexes
WHERE [id] = @objid
AND [indid] > 0
AND [indid] < 255
AND ([status] & 64) = 0
ORDER BY indid
OPEN ms_crs_ind
FETCH ms_crs_ind
INTO @indid,
@groupid,
@indname,
@status
-- IF NO INDEX, QUIT
IF @@FETCH_STATUS < 0
BEGIN
DEALLOCATE ms_crs_ind
RAISERROR(15472, -1, -1) --'Object does not have any indexes.'
RETURN (0)
END
-- create temp table
CREATE TABLE #spindtab
(
[index_id] INT NOT NULL,
[index_name] sysname COLLATE DATABASE_DEFAULT NOT NULL,
[stats] INT NULL,
[groupname] sysname COLLATE DATABASE_DEFAULT NOT NULL,
[index_keys] NVARCHAR(2126) COLLATE DATABASE_DEFAULT NOT NULL -- see @keys above for length descr
)
-- Now check out each index, figure out its type and keys and
-- save the info in a temporary table that we'll print out at the end.
WHILE @@FETCH_STATUS >= 0
BEGIN
-- First we'll figure out what the keys are.
DECLARE @i INT,
@thiskey NVARCHAR(131) -- 128+3
SELECT @keys = QUOTENAME(INDEX_COL(@objname, @indid, 1), N']'),
@i = 2
IF (INDEXKEY_PROPERTY(@objid, @indid, 1, 'IsDescending') = 1)
SELECT @keys = @keys + N'(-)'
SELECT @thiskey = INDEX_COL(@objname, @indid, @i)
IF (
(@thiskey IS NOT NULL)
AND (INDEXKEY_PROPERTY(@objid, @indid, @i, 'IsDescending') = 1)
)
SELECT @thiskey = @thiskey + N'(-)'
WHILE (@thiskey IS NOT NULL)
BEGIN
SELECT @keys = @keys + N', ' + QUOTENAME(@thiskey, N']'),
@i = @i + 1
SELECT @thiskey = INDEX_COL(@objname, @indid, @i)
IF (
(@thiskey IS NOT NULL)
AND (INDEXKEY_PROPERTY(@objid, @indid, @i, 'IsDescending') = 1)
)
SELECT @thiskey = @thiskey + N'(-)'
END
SELECT @groupname = groupname
FROM sysfilegroups
WHERE groupid = @groupid
-- INSERT ROW FOR INDEX
INSERT INTO #spindtab
VALUES
(@indid, @indname, @status, @groupname, @keys)
-- Next index
FETCH ms_crs_ind
INTO @indid,
@groupid,
@indname,
@status
END
DEALLOCATE ms_crs_ind
-- SET UP SOME CONSTANT VALUES FOR OUTPUT QUERY
DECLARE @empty VARCHAR(1)
SELECT @empty = ''
DECLARE @des1 VARCHAR(35), -- 35 matches spt_values
@des2 VARCHAR(35),
@des4 VARCHAR(35),
@des32 VARCHAR(35),
@des64 VARCHAR(35),
@des2048 VARCHAR(35),
@des4096 VARCHAR(35),
@des8388608 VARCHAR(35),
@des16777216 VARCHAR(35)
SELECT @des1 = [name]
FROM master.dbo.spt_values
WHERE [type] = 'I'
AND [number] = 1
SELECT @des2 = [name]
FROM master.dbo.spt_values
WHERE [type] = 'I'
AND [number] = 2
SELECT @des4 = [name]
FROM master.dbo.spt_values
WHERE [type] = 'I'
AND [number] = 4
SELECT @des32 = [name]
FROM master.dbo.spt_values
WHERE [type] = 'I'
AND [number] = 32
SELECT @des64 = [name]
FROM master.dbo.spt_values
WHERE [type] = 'I'
AND [number] = 64
SELECT @des2048 = [name]
FROM master.dbo.spt_values
WHERE [type] = 'I'
AND [number] = 2048
SELECT @des4096 = [name]
FROM master.dbo.spt_values
WHERE [type] = 'I'
AND [number] = 4096
SELECT @des8388608 = [name]
FROM master.dbo.spt_values
WHERE [type] = 'I'
AND [number] = 8388608
SELECT @des16777216 = [name]
FROM master.dbo.spt_values
WHERE [type] = 'I'
AND [number] = 16777216
-- Simple workaround to establish the tree-level columns included
DECLARE @clustered_index NVARCHAR(4000)
DECLARE @uniquifier BIT
SELECT @clustered_index = ISNULL(index_keys, 'RID'),
@uniquifier = CASE
WHEN index_keys IS NOT NULL
AND (stats & 2) = 0 THEN
1
ELSE
0
END
FROM #spindtab
WHERE index_id = 1
-- DISPLAY THE RESULTS
--(stats & 1) <> 0 = ignore_duplicate_keys
--(stats & 2) <> 0 = unique
--(stats & 4) <> 0 = ignore_duplicate_rows
--(stats & 16) <> 0 = clustered
--(stats & 32) <> 0 = hypothetical
--(stats & 64) <> 0 statistics
--(stats & 2048) <> 0 = primary_key
--(stats & 4096) <> 0 = unique_key
--(stats & 8388608) <> 0 = auto_create
--(stats & 16777216) <> 0 = stats_no_recompute
SELECT index_id,
index_name,
CONVERT( VARCHAR(210), --bits 16 off, 1, 2, 16777216 on, located on group
CASE
WHEN (stats & 16) <> 0 THEN
'clustered'
ELSE
'nonclustered'
END + CASE
WHEN (stats & 1) <> 0 THEN
', ' + @des1
ELSE
@empty
END + CASE
WHEN (stats & 2) <> 0 THEN
', ' + @des2
ELSE
@empty
END + CASE
WHEN (stats & 4) <> 0 THEN
', ' + @des4
ELSE
@empty
END + CASE
WHEN (stats & 64) <> 0 THEN
', ' + @des64
ELSE
CASE
WHEN (stats & 32) <> 0 THEN
', ' + @des32
ELSE
@empty
END
END + CASE
WHEN (stats & 2048) <> 0 THEN
', ' + @des2048
ELSE
@empty
END + CASE
WHEN (stats & 4096) <> 0 THEN
', ' + @des4096
ELSE
@empty
END + CASE
WHEN (stats & 8388608) <> 0 THEN
', ' + @des8388608
ELSE
@empty
END + CASE
WHEN (stats & 16777216) <> 0 THEN
', ' + @des16777216
ELSE
@empty
END + ' located on ' + groupname
) AS [index_description],
index_keys,
CASE
WHEN (stats & 2) = 0 /*non unique*/
AND (stats & 16) = 0 /*non-clustered*/
AND @uniquifier = 0 THEN
index_keys + ', ' + ISNULL(@clustered_index, 'RID')
WHEN (stats & 2) = 0 /*non unique*/
AND (stats & 16) = 0 /*non-clustered*/
AND @uniquifier = 1 THEN
index_keys + ', ' + ISNULL(@clustered_index, 'RID') + ', UNIQUIFIER'
WHEN (stats & 2) = 0 /*non unique*/
AND (stats & 16) <> 0 /*clustered*/
THEN
index_keys + ', UNIQUIFIER'
WHEN @clustered_index IS NOT NULL
AND @uniquifier = 0 THEN
index_keys
ELSE
index_keys + ', RID'
END AS [columns_in_tree],
CASE
WHEN (stats & 2048) <> 0 THEN
'All columns "included" - the leaf level IS the data row.'
WHEN (stats & 4096) <> 0 THEN
index_keys + ', ' + @clustered_index
WHEN (stats & 2) = 0 /*non unique*/
AND (stats & 16) = 0 /*non-clustered*/
AND @uniquifier = 0 THEN
index_keys + ', ' + ISNULL(@clustered_index, 'RID')
WHEN (stats & 2) = 0 /*non unique*/
AND (stats & 16) = 0 /*non-clustered*/
AND @uniquifier = 1 THEN
index_keys + ', ' + ISNULL(@clustered_index, 'RID') + ', UNIQUIFIER'
WHEN (stats & 2) = 0 /*non unique*/
AND (stats & 16) <> 0 /*clustered*/
THEN
'All columns "included" - the leaf level IS the data row.'
WHEN (stats & 2) <> 0 /*unique*/
AND (stats & 16) = 0 /*non-clustered*/
THEN
index_keys
ELSE
index_keys + ', RID'
END AS [columns_in_leaf]
FROM #spindtab
ORDER BY index_id
DROP TABLE #spindtab
RETURN (0) -- sp_helpindex
END
GO
EXEC sp_MS_marksystemobject 'dbo.sp_SQL2000_helpindex'
GO