Skip to content

Commit 27d2ee4

Browse files
sp_IndexCleanup: stage dm_db_index_usage_stats to avoid repeated DMV scans
The LEFT JOIN to dm_db_index_usage_stats was executed via nested loops, scanning the full DMV per row (52M actual rows, ~4 minutes). Now pre-stages the DMV for the current database into #usage_stats with a clustered PK on (object_id, index_id) before the main query, then LEFT JOINs to the temp table instead. Handles the database cursor loop with TRUNCATE on re-entry. Tested on SQL2022 (StackOverflow2013) and SQL2016 (StackOverflow2010). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ddbbe5c commit 27d2ee4

1 file changed

Lines changed: 53 additions & 2 deletions

File tree

sp_IndexCleanup/sp_IndexCleanup.sql

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2117,6 +2117,58 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21172117
RAISERROR('Generating #index_details insert', 0, 0) WITH NOWAIT;
21182118
END;
21192119

2120+
/*Stage dm_db_index_usage_stats for this database to avoid repeated DMV scans*/
2121+
IF OBJECT_ID(N'tempdb..#usage_stats') IS NOT NULL
2122+
BEGIN
2123+
TRUNCATE TABLE #usage_stats;
2124+
END;
2125+
ELSE
2126+
BEGIN
2127+
CREATE TABLE
2128+
#usage_stats
2129+
(
2130+
object_id int NOT NULL,
2131+
index_id int NOT NULL,
2132+
user_seeks bigint NOT NULL,
2133+
user_scans bigint NOT NULL,
2134+
user_lookups bigint NOT NULL,
2135+
user_updates bigint NOT NULL,
2136+
last_user_seek datetime NULL,
2137+
last_user_scan datetime NULL,
2138+
last_user_lookup datetime NULL,
2139+
last_user_update datetime NULL,
2140+
PRIMARY KEY CLUSTERED (object_id, index_id)
2141+
);
2142+
END;
2143+
2144+
INSERT
2145+
#usage_stats WITH (TABLOCK)
2146+
(
2147+
object_id,
2148+
index_id,
2149+
user_seeks,
2150+
user_scans,
2151+
user_lookups,
2152+
user_updates,
2153+
last_user_seek,
2154+
last_user_scan,
2155+
last_user_lookup,
2156+
last_user_update
2157+
)
2158+
SELECT
2159+
us.object_id,
2160+
us.index_id,
2161+
us.user_seeks,
2162+
us.user_scans,
2163+
us.user_lookups,
2164+
us.user_updates,
2165+
us.last_user_seek,
2166+
us.last_user_scan,
2167+
us.last_user_lookup,
2168+
us.last_user_update
2169+
FROM sys.dm_db_index_usage_stats AS us
2170+
WHERE us.database_id = @current_database_id;
2171+
21202172
SELECT
21212173
@sql = N'
21222174
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
@@ -2238,10 +2290,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22382290
N'.sys.columns AS c
22392291
ON ic.object_id = c.object_id
22402292
AND ic.column_id = c.column_id
2241-
LEFT JOIN sys.dm_db_index_usage_stats AS us
2293+
LEFT JOIN #usage_stats AS us
22422294
ON i.object_id = us.object_id
22432295
AND i.index_id = us.index_id
2244-
AND us.database_id = @database_id
22452296
WHERE (t.object_id IS NULL OR t.is_ms_shipped = 0)
22462297
AND i.type IN (1, 2)
22472298
AND i.is_disabled = 0

0 commit comments

Comments
 (0)