Skip to content

Commit 6e6673e

Browse files
Merge pull request #723 from erikdarlingdata/dev
sp_IndexCleanup: performance + bug fix #721
2 parents ddbbe5c + c05bce1 commit 6e6673e

1 file changed

Lines changed: 92 additions & 56 deletions

File tree

sp_IndexCleanup/sp_IndexCleanup.sql

Lines changed: 92 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,9 +1447,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14471447
schema_id = s.schema_id,
14481448
schema_name = s.name,
14491449
object_id = i.object_id,
1450-
table_name = ISNULL(t.name, v.name),
1450+
table_name = o.name,
14511451
index_id = i.index_id,
1452-
index_name = ISNULL(i.name, ISNULL(t.name, v.name) + N''.Heap''),
1452+
index_name = ISNULL(i.name, o.name + N''.Heap''),
14531453
can_compress =
14541454
CASE
14551455
WHEN p.index_id > 0
@@ -1458,20 +1458,18 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14581458
ELSE 0
14591459
END
14601460
FROM ' + QUOTENAME(@current_database_name) + N'.sys.indexes AS i
1461-
LEFT JOIN ' + QUOTENAME(@current_database_name) + N'.sys.tables AS t
1462-
ON i.object_id = t.object_id
1463-
LEFT JOIN ' + QUOTENAME(@current_database_name) + N'.sys.views AS v
1464-
ON i.object_id = v.object_id
1461+
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.objects AS o
1462+
ON i.object_id = o.object_id
14651463
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.schemas AS s
1466-
ON ISNULL(t.schema_id, v.schema_id) = s.schema_id
1464+
ON o.schema_id = s.schema_id
14671465
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.partitions AS p
14681466
ON i.object_id = p.object_id
14691467
AND i.index_id = p.index_id
14701468
/* LEFT JOIN to dm_db_index_usage_stats removed 2026-01-15 - was dead code with no columns selected */
1471-
WHERE (t.object_id IS NULL OR t.is_ms_shipped = 0)
1472-
AND (t.object_id IS NULL OR t.type <> N''TF'')
1473-
AND i.is_disabled = 0
1474-
AND i.is_hypothetical = 0';
1469+
WHERE o.is_ms_shipped = 0
1470+
AND o.type IN (N''U'', N''V'')
1471+
AND i.is_disabled = 0
1472+
AND i.is_hypothetical = 0';
14751473

14761474
IF @supports_temporal_tables = 1
14771475
BEGIN
@@ -1971,9 +1969,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19711969
schema_id = s.schema_id,
19721970
schema_name = s.name,
19731971
os.object_id,
1974-
table_name = ISNULL(t.name, v.name),
1972+
table_name = o.name,
19751973
os.index_id,
1976-
index_name = ISNULL(i.name, ISNULL(t.name, v.name) + N''.Heap''),
1974+
index_name = ISNULL(i.name, o.name + N''.Heap''),
19771975
range_scan_count = SUM(os.range_scan_count),
19781976
singleton_lookup_count = SUM(os.singleton_lookup_count),
19791977
forwarded_fetch_count = SUM(os.forwarded_fetch_count),
@@ -2011,12 +2009,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20112009
NULL,
20122010
NULL
20132011
) AS os
2014-
LEFT JOIN ' + QUOTENAME(@current_database_name) + N'.sys.tables AS t
2015-
ON os.object_id = t.object_id
2016-
LEFT JOIN ' + QUOTENAME(@current_database_name) + N'.sys.views AS v
2017-
ON os.object_id = v.object_id
2012+
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.objects AS o
2013+
ON os.object_id = o.object_id
20182014
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.schemas AS s
2019-
ON ISNULL(t.schema_id, v.schema_id) = s.schema_id
2015+
ON o.schema_id = s.schema_id
20202016
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.indexes AS i
20212017
ON os.object_id = i.object_id
20222018
AND os.index_id = i.index_id
@@ -2034,7 +2030,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20342030
s.schema_id,
20352031
s.name,
20362032
os.object_id,
2037-
ISNULL(t.name, v.name),
2033+
o.name,
20382034
os.index_id,
20392035
i.name
20402036
OPTION(RECOMPILE);
@@ -2117,6 +2113,66 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21172113
RAISERROR('Generating #index_details insert', 0, 0) WITH NOWAIT;
21182114
END;
21192115

2116+
/*Stage dm_db_index_usage_stats for this database to avoid repeated DMV scans*/
2117+
IF OBJECT_ID(N'tempdb..#usage_stats') IS NOT NULL
2118+
BEGIN
2119+
TRUNCATE TABLE #usage_stats;
2120+
END;
2121+
ELSE
2122+
BEGIN
2123+
CREATE TABLE
2124+
#usage_stats
2125+
(
2126+
object_id int NOT NULL,
2127+
index_id int NOT NULL,
2128+
user_seeks bigint NOT NULL,
2129+
user_scans bigint NOT NULL,
2130+
user_lookups bigint NOT NULL,
2131+
user_updates bigint NOT NULL,
2132+
last_user_seek datetime NULL,
2133+
last_user_scan datetime NULL,
2134+
last_user_lookup datetime NULL,
2135+
last_user_update datetime NULL,
2136+
PRIMARY KEY CLUSTERED (object_id, index_id)
2137+
);
2138+
END;
2139+
2140+
INSERT
2141+
#usage_stats WITH (TABLOCK)
2142+
(
2143+
object_id,
2144+
index_id,
2145+
user_seeks,
2146+
user_scans,
2147+
user_lookups,
2148+
user_updates,
2149+
last_user_seek,
2150+
last_user_scan,
2151+
last_user_lookup,
2152+
last_user_update
2153+
)
2154+
SELECT
2155+
us.object_id,
2156+
us.index_id,
2157+
us.user_seeks,
2158+
us.user_scans,
2159+
us.user_lookups,
2160+
us.user_updates,
2161+
us.last_user_seek,
2162+
us.last_user_scan,
2163+
us.last_user_lookup,
2164+
us.last_user_update
2165+
FROM sys.dm_db_index_usage_stats AS us
2166+
WHERE us.database_id = @current_database_id
2167+
AND EXISTS
2168+
(
2169+
SELECT
2170+
1/0
2171+
FROM #filtered_objects AS fo
2172+
WHERE fo.database_id = @current_database_id
2173+
AND fo.object_id = us.object_id
2174+
);
2175+
21202176
SELECT
21212177
@sql = N'
21222178
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
@@ -2128,24 +2184,16 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21282184
i.index_id,
21292185
s.schema_id,
21302186
schema_name = s.name,
2131-
table_name = ISNULL(t.name, v.name),
2132-
index_name = ISNULL(i.name, ISNULL(t.name, v.name) + N''.Heap''),
2187+
table_name = o.name,
2188+
index_name = ISNULL(i.name, o.name + N''.Heap''),
21332189
column_name = c.name,
21342190
column_id = c.column_id,
21352191
i.is_primary_key,
21362192
i.is_unique,
21372193
i.is_unique_constraint,
21382194
is_indexed_view =
21392195
CASE
2140-
WHEN EXISTS
2141-
(
2142-
SELECT
2143-
1/0
2144-
FROM ' + QUOTENAME(@current_database_name) + N'.sys.objects AS so
2145-
WHERE i.object_id = so.object_id
2146-
AND so.is_ms_shipped = 0
2147-
AND so.type = ''V''
2148-
)
2196+
WHEN o.type = ''V''
21492197
THEN 1
21502198
ELSE 0
21512199
END,
@@ -2222,12 +2270,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22222270
THEN 0
22232271
END
22242272
FROM ' + QUOTENAME(@current_database_name) + N'.sys.indexes AS i
2225-
LEFT JOIN ' + QUOTENAME(@current_database_name) + N'.sys.tables AS t
2226-
ON i.object_id = t.object_id
2227-
LEFT JOIN ' + QUOTENAME(@current_database_name) + N'.sys.views AS v
2228-
ON i.object_id = v.object_id
2273+
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.objects AS o
2274+
ON i.object_id = o.object_id
22292275
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.schemas AS s
2230-
ON ISNULL(t.schema_id, v.schema_id) = s.schema_id
2276+
ON o.schema_id = s.schema_id
22312277
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.index_columns AS ic
22322278
ON i.object_id = ic.object_id
22332279
AND i.index_id = ic.index_id
@@ -2238,11 +2284,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22382284
N'.sys.columns AS c
22392285
ON ic.object_id = c.object_id
22402286
AND ic.column_id = c.column_id
2241-
LEFT JOIN sys.dm_db_index_usage_stats AS us
2287+
LEFT JOIN #usage_stats AS us
22422288
ON i.object_id = us.object_id
22432289
AND i.index_id = us.index_id
2244-
AND us.database_id = @database_id
2245-
WHERE (t.object_id IS NULL OR t.is_ms_shipped = 0)
2290+
WHERE o.is_ms_shipped = 0
2291+
AND o.type IN (N''U'', N''V'')
22462292
AND i.type IN (1, 2)
22472293
AND i.is_disabled = 0
22482294
AND i.is_hypothetical = 0
@@ -2407,8 +2453,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24072453
ps.index_id,
24082454
s.schema_id,
24092455
schema_name = s.name,
2410-
table_name = ISNULL(t.name, v.name),
2411-
index_name = ISNULL(i.name, ISNULL(t.name, v.name) + N''.Heap''),
2456+
table_name = o.name,
2457+
index_name = ISNULL(i.name, o.name + N''.Heap''),
24122458
ps.partition_id,
24132459
p.partition_number,
24142460
total_rows = ps.row_count,
@@ -2418,20 +2464,18 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24182464
p.data_compression_desc,
24192465
i.data_space_id
24202466
FROM ' + QUOTENAME(@current_database_name) + N'.sys.indexes AS i
2421-
LEFT JOIN ' + QUOTENAME(@current_database_name) + N'.sys.tables AS t
2422-
ON i.object_id = t.object_id
2423-
LEFT JOIN ' + QUOTENAME(@current_database_name) + N'.sys.views AS v
2424-
ON i.object_id = v.object_id
2467+
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.objects AS o
2468+
ON i.object_id = o.object_id
24252469
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.schemas AS s
2426-
ON ISNULL(t.schema_id, v.schema_id) = s.schema_id
2470+
ON o.schema_id = s.schema_id
24272471
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.partitions AS p
24282472
ON i.object_id = p.object_id
24292473
AND i.index_id = p.index_id
24302474
JOIN ' + QUOTENAME(@current_database_name) + N'.sys.allocation_units AS a
24312475
ON p.partition_id = a.container_id
24322476
LEFT HASH JOIN ' + QUOTENAME(@current_database_name) + N'.sys.dm_db_partition_stats AS ps
24332477
ON p.partition_id = ps.partition_id
2434-
WHERE (t.object_id IS NULL OR t.type <> N''TF'')
2478+
WHERE o.type IN (N''U'', N''V'')
24352479
AND i.type IN (1, 2)
24362480
AND EXISTS
24372481
(
@@ -2460,7 +2504,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24602504
ps.index_id,
24612505
s.schema_id,
24622506
s.name,
2463-
ISNULL(t.name, v.name),
2507+
o.name,
24642508
i.name,
24652509
ps.partition_id,
24662510
p.partition_number,
@@ -3174,7 +3218,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31743218
AND NOT (ia1.is_unique = 1 AND ia2.is_unique = 0)
31753219
WHERE ia1.consolidation_rule IS NULL /* Not already processed */
31763220
AND ia2.consolidation_rule IS NULL /* Not already processed */
3177-
/* Exclude unique constraints - we'll handle those separately in Rule 7 */
3221+
/* Don't disable unique constraints — but allow them as the wider (target) index */
31783222
AND NOT EXISTS
31793223
(
31803224
SELECT
@@ -3183,14 +3227,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31833227
WHERE id1_uc.index_hash = ia1.index_hash
31843228
AND id1_uc.is_unique_constraint = 1
31853229
)
3186-
AND NOT EXISTS
3187-
(
3188-
SELECT
3189-
1/0
3190-
FROM #index_details AS id2_uc
3191-
WHERE id2_uc.index_hash = ia2.index_hash
3192-
AND id2_uc.is_unique_constraint = 1
3193-
)
31943230
AND EXISTS
31953231
(
31963232
SELECT

0 commit comments

Comments
 (0)