|
| 1 | +/*============================================================================ |
| 2 | + File: sp_SQLskills_SQL2000_finddupes.sql |
| 3 | +
|
| 4 | + Summary: Run against a single database this procedure will list ALL |
| 5 | + duplicate indexes and the needed TSQL to drop them! |
| 6 | +
|
| 7 | + See: https://www.sqlskills.com/blogs/kimberly/removing-duplicate-indexes/ |
| 8 | +
|
| 9 | + Date: 29 September 2017 |
| 10 | +
|
| 11 | + SQL Server Versions: |
| 12 | + SQL Server 2000 |
| 13 | +------------------------------------------------------------------------------ |
| 14 | + Written by Randolph West, bornsql.ca |
| 15 | + Based on scripts developed by Kimberly L. Tripp, SQLSkills.com. |
| 16 | +
|
| 17 | + Copyright (c) Born SQL. |
| 18 | +
|
| 19 | + You may alter this code for your own *non-commercial* purposes. You may |
| 20 | + republish altered code as long as you include this copyright and give due |
| 21 | + credit, but you must obtain prior permission before blogging this code. |
| 22 | +
|
| 23 | + THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF |
| 24 | + ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED |
| 25 | + TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A |
| 26 | + PARTICULAR PURPOSE. |
| 27 | +============================================================================*/ |
| 28 | +USE master |
| 29 | +GO |
| 30 | + |
| 31 | +IF OBJECTPROPERTY(OBJECT_ID('sp_SQLskills_SQL2000_finddupes'), 'IsProcedure') = 1 |
| 32 | + DROP PROCEDURE sp_SQLskills_SQL2000_finddupes |
| 33 | +GO |
| 34 | + |
| 35 | +SET ANSI_NULLS ON |
| 36 | +GO |
| 37 | + |
| 38 | +SET QUOTED_IDENTIFIER ON |
| 39 | +GO |
| 40 | + |
| 41 | +CREATE PROCEDURE [dbo].[sp_SQLskills_SQL2000_finddupes] ( |
| 42 | + @ObjName NVARCHAR(776) = NULL -- the table to check for duplicates |
| 43 | + -- when NULL it will check ALL tables |
| 44 | + ) |
| 45 | +AS |
| 46 | + |
| 47 | +-- September 2017: Moved to GitHub from personal site. |
| 48 | + |
| 49 | +-- August 2012: Updated copyright bits, cleaned up formatting and |
| 50 | +-- comments. |
| 51 | + |
| 52 | +-- March 2012: Based on SQL Server 2000 sp_helpindex with revised |
| 53 | +-- code for columns in index levels. |
| 54 | + |
| 55 | +-- For the original script, updates and/or additional information, see |
| 56 | +-- https://www.sqlskills.com/blogs/kimberly/ (Kimberly L. Tripp) |
| 57 | + |
| 58 | +-- For updates to this port of the script, see this file: |
| 59 | +-- https://github.com/bornsql/scripts/sp_SQLskills_SQL2000_finddupes.sql |
| 60 | + |
| 61 | +SET NOCOUNT ON |
| 62 | + |
| 63 | +DECLARE @ObjID INT, -- the object id of the table |
| 64 | + @DBName SYSNAME, |
| 65 | + @SchemaName SYSNAME, |
| 66 | + @TableName SYSNAME, |
| 67 | + @ExecStr NVARCHAR(4000) |
| 68 | + |
| 69 | +-- Check to see that the object names are local to the current database. |
| 70 | +SELECT @DBName = PARSENAME(@ObjName, 3) |
| 71 | + |
| 72 | +IF @DBName IS NULL |
| 73 | + SELECT @DBName = DB_NAME() |
| 74 | +ELSE |
| 75 | + IF @DBName <> DB_NAME() |
| 76 | + BEGIN |
| 77 | + RAISERROR (15250, -1, -1) |
| 78 | + -- select * from sys.messages where message_id = 15250 |
| 79 | + RETURN (1) |
| 80 | + END |
| 81 | + |
| 82 | +IF @DBName IN (N'tempdb') |
| 83 | +BEGIN |
| 84 | + RAISERROR ('WARNING: This procedure cannot be run against tempdb. Skipping database.', 10, 0) |
| 85 | + RETURN (1) |
| 86 | +END |
| 87 | + |
| 88 | +-- Check to see the the table exists and initialize @ObjID. |
| 89 | +SELECT @SchemaName = PARSENAME(@ObjName, 2) |
| 90 | + |
| 91 | +IF @SchemaName IS NULL |
| 92 | + SELECT @SchemaName = 'dbo' |
| 93 | + |
| 94 | +-- Check to see the the table exists and initialize @ObjID. |
| 95 | +IF @ObjName IS NOT NULL |
| 96 | +BEGIN |
| 97 | + SELECT @ObjID = OBJECT_ID(@ObjName) |
| 98 | + |
| 99 | + IF @ObjID IS NULL |
| 100 | + BEGIN |
| 101 | + RAISERROR (15009, -1, -1, @ObjName, @DBName) |
| 102 | + -- select * from sys.messages where message_id = 15009 |
| 103 | + RETURN (1) |
| 104 | + END |
| 105 | +END |
| 106 | + |
| 107 | +CREATE TABLE #DropIndexes ( |
| 108 | + DatabaseName SYSNAME, |
| 109 | + SchemaName SYSNAME, |
| 110 | + TableName SYSNAME, |
| 111 | + IndexName SYSNAME, |
| 112 | + DropStatement NVARCHAR(2000) |
| 113 | +) |
| 114 | + |
| 115 | +-- Very hacky method to work around the VARCHAR(MAX) code in the |
| 116 | +-- original script. This may need modification in the case of |
| 117 | +-- very wide indexes and / or index names. |
| 118 | + |
| 119 | +CREATE TABLE #FindDupes ( |
| 120 | + index_id INT, |
| 121 | + index_name SYSNAME, |
| 122 | + index_description VARCHAR(210), |
| 123 | + index_keys NVARCHAR(1200), |
| 124 | + columns_in_tree NVARCHAR(1200), |
| 125 | + columns_in_leaf NVARCHAR(1200) |
| 126 | +) |
| 127 | + |
| 128 | +-- OPEN CURSOR OVER TABLE(S) |
| 129 | +IF @ObjName IS NOT NULL |
| 130 | +BEGIN |
| 131 | + DECLARE TableCursor CURSOR LOCAL STATIC |
| 132 | + FOR SELECT |
| 133 | + @SchemaName, |
| 134 | + PARSENAME(@ObjName, 1) |
| 135 | +END |
| 136 | +ELSE |
| 137 | +BEGIN |
| 138 | + DECLARE TableCursor CURSOR LOCAL STATIC |
| 139 | + FOR SELECT |
| 140 | + u.NAME, |
| 141 | + t.NAME |
| 142 | + FROM sysobjects t |
| 143 | + INNER JOIN sysusers u ON t.uid = u.uid |
| 144 | + WHERE t.type = 'U' --AND name |
| 145 | + ORDER BY |
| 146 | + u.NAME, |
| 147 | + t.NAME |
| 148 | +END |
| 149 | + |
| 150 | +OPEN TableCursor |
| 151 | + |
| 152 | +FETCH TableCursor |
| 153 | +INTO @SchemaName, |
| 154 | + @TableName |
| 155 | + |
| 156 | +-- For each table, list the add the duplicate indexes and save |
| 157 | +-- the info in a temporary table that we'll print out at the end. |
| 158 | +WHILE @@FETCH_STATUS >= 0 |
| 159 | +BEGIN |
| 160 | + TRUNCATE TABLE #FindDupes |
| 161 | + |
| 162 | + SELECT @ExecStr = 'EXEC sp_SQLskills_SQL2000_helpindex ''' + QUOTENAME(@SchemaName) + N'.' + QUOTENAME(@TableName) + N'''' |
| 163 | + |
| 164 | + --SELECT @ExecStr |
| 165 | + INSERT #FindDupes |
| 166 | + EXEC (@ExecStr) |
| 167 | + |
| 168 | + --SELECT * FROM #FindDupes |
| 169 | + INSERT #DropIndexes |
| 170 | + SELECT DISTINCT @DBName, |
| 171 | + @SchemaName, |
| 172 | + @TableName, |
| 173 | + t1.index_name, |
| 174 | + N'DROP INDEX ' + QUOTENAME(@SchemaName, N']') + N'.' + QUOTENAME(@TableName, N']') + N'.' + t1.index_name |
| 175 | + FROM #FindDupes AS t1 |
| 176 | + JOIN #FindDupes AS t2 ON t1.columns_in_tree = t2.columns_in_tree |
| 177 | + AND t1.columns_in_leaf = t2.columns_in_leaf |
| 178 | + AND PATINDEX('%unique%', t1.index_description) = PATINDEX('%unique%', t2.index_description) |
| 179 | + AND t1.index_id > t2.index_id |
| 180 | + |
| 181 | + FETCH TableCursor |
| 182 | + INTO @SchemaName, |
| 183 | + @TableName |
| 184 | +END |
| 185 | + |
| 186 | +DEALLOCATE TableCursor |
| 187 | + |
| 188 | +-- DISPLAY THE RESULTS |
| 189 | +/* RAISERROR replaced with a SELECT */ |
| 190 | +IF ( |
| 191 | + SELECT COUNT(*) |
| 192 | + FROM #DropIndexes |
| 193 | + ) = 0 |
| 194 | + -- RAISERROR('Database: %s has NO duplicate indexes.', 10, 0, @DBName) |
| 195 | + SELECT 'Database ' + @DBName + ' has NO duplicate indexes.' AS [Results] |
| 196 | +ELSE |
| 197 | + SELECT * |
| 198 | + FROM #DropIndexes |
| 199 | + ORDER BY |
| 200 | + SchemaName, |
| 201 | + TableName |
| 202 | + |
| 203 | +RETURN (0) -- sp_SQLskills_SQL2000_finddupes |
| 204 | +GO |
| 205 | + |
| 206 | +EXEC sp_MS_marksystemobject 'dbo.sp_SQLskills_SQL2000_finddupes' |
| 207 | +GO |
0 commit comments