Skip to content

Commit 7e48494

Browse files
Fix query_stats collector causing SQL dumps on passive mirrors (#632)
Removed CROSS APPLY sys.dm_exec_plan_attributes and the direct sys.databases join. Both dm_exec_plan_attributes and dm_exec_sql_text can trigger severity 22 engine crashes when plan handles reference RESTORING databases on passive mirror servers. Now pre-builds a temp table of ONLINE, accessible database IDs (filtered by state = 0 + HAS_DBACCESS) before the main query runs. The staging INSERT joins to this temp table instead of sys.databases, preventing any DMV from being evaluated against RESTORING databases. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9a673cf commit 7e48494

1 file changed

Lines changed: 35 additions & 17 deletions

File tree

install/08_collect_query_stats.sql

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,38 @@ BEGIN
222222
row_hash binary(32) NULL
223223
);
224224

225+
/*
226+
Pre-build list of ONLINE, accessible database IDs.
227+
This prevents any downstream DMV calls (dm_exec_sql_text,
228+
dm_exec_plan_attributes) from touching RESTORING databases
229+
on passive mirror servers — which triggers severity 22 dumps.
230+
*/
231+
CREATE TABLE
232+
#online_databases
233+
(
234+
database_id integer NOT NULL PRIMARY KEY,
235+
database_name sysname NOT NULL
236+
);
237+
238+
INSERT INTO
239+
#online_databases
240+
(
241+
database_id,
242+
database_name
243+
)
244+
SELECT
245+
d.database_id,
246+
d.name
247+
FROM sys.databases AS d
248+
WHERE d.state = 0
249+
AND HAS_DBACCESS(d.name) = 1
250+
AND d.database_id NOT IN
251+
(
252+
1, 2, 3, 4, 32761, 32767,
253+
DB_ID(N'PerformanceMonitor')
254+
)
255+
AND d.database_id < 32761;
256+
225257
INSERT INTO
226258
#query_stats_staging
227259
(
@@ -274,7 +306,7 @@ BEGIN
274306
)
275307
SELECT
276308
server_start_time = @server_start_time,
277-
database_name = d.name,
309+
database_name = od.database_name,
278310
sql_handle = qs.sql_handle,
279311
statement_start_offset = qs.statement_start_offset,
280312
statement_end_offset = qs.statement_end_offset,
@@ -353,23 +385,9 @@ BEGIN
353385
qs.statement_start_offset,
354386
qs.statement_end_offset
355387
) AS tqp
356-
CROSS APPLY
357-
(
358-
SELECT
359-
dbid = CONVERT(integer, pa.value)
360-
FROM sys.dm_exec_plan_attributes(qs.plan_handle) AS pa
361-
WHERE pa.attribute = N'dbid'
362-
) AS pa
363-
INNER JOIN sys.databases AS d
364-
ON pa.dbid = d.database_id
388+
INNER JOIN #online_databases AS od
389+
ON st.dbid = od.database_id
365390
WHERE qs.last_execution_time >= @cutoff_time
366-
AND d.state = 0 /*ONLINE only — skip RESTORING databases (mirroring/AG secondary)*/
367-
AND pa.dbid NOT IN
368-
(
369-
1, 2, 3, 4, 32761, 32767,
370-
DB_ID(N'PerformanceMonitor')
371-
)
372-
AND pa.dbid < 32761 /*exclude contained AG system databases*/
373391
OPTION(RECOMPILE);
374392

375393
/*

0 commit comments

Comments
 (0)