Skip to content

Commit 110e587

Browse files
Merge pull request #754 from erikdarlingdata/dev
Merge dev to main: sp_QuickieCache modes and filter fix
2 parents 1ab3c31 + 03a594d commit 110e587

1 file changed

Lines changed: 144 additions & 2 deletions

File tree

sp_QuickieCache/sp_QuickieCache.sql

Lines changed: 144 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ ALTER PROCEDURE
6262
@minimum_execution_count bigint = 2, /*noise floor for single-exec queries*/
6363
@ignore_system_databases bit = 1, /*exclude master, model, msdb, tempdb*/
6464
@impact_threshold decimal(3, 2) = 0.50, /*minimum impact_score to surface (0.00-1.00)*/
65+
@find_single_use_plans bit = 0, /*show single-use plans consuming the most memory*/
66+
@find_duplicate_plans bit = 0, /*show query hashes with multiple cached plans*/
6567
@debug bit = 0, /*print diagnostics*/
6668
@help bit = 0, /*display parameter help*/
6769
@version varchar(30) = NULL OUTPUT, /*OUTPUT; for support*/
@@ -122,6 +124,10 @@ BEGIN
122124
THEN N'exclude system databases (master, model, msdb, tempdb)'
123125
WHEN N'@impact_threshold'
124126
THEN N'minimum impact_score to surface in results'
127+
WHEN N'@find_single_use_plans'
128+
THEN N'show single-use plans consuming the most memory'
129+
WHEN N'@find_duplicate_plans'
130+
THEN N'show query hashes with multiple cached plans'
125131
WHEN N'@debug'
126132
THEN N'print diagnostic information'
127133
WHEN N'@help'
@@ -150,6 +156,10 @@ BEGIN
150156
THEN N'0 or 1'
151157
WHEN N'@impact_threshold'
152158
THEN N'0.00 to 1.00'
159+
WHEN N'@find_single_use_plans'
160+
THEN N'0 or 1'
161+
WHEN N'@find_duplicate_plans'
162+
THEN N'0 or 1'
153163
WHEN N'@debug'
154164
THEN N'0 or 1'
155165
WHEN N'@help'
@@ -178,6 +188,10 @@ BEGIN
178188
THEN N'1'
179189
WHEN N'@impact_threshold'
180190
THEN N'0.50'
191+
WHEN N'@find_single_use_plans'
192+
THEN N'0'
193+
WHEN N'@find_duplicate_plans'
194+
THEN N'0'
181195
WHEN N'@debug'
182196
THEN N'0'
183197
WHEN N'@help'
@@ -326,6 +340,134 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
326340
RETURN;
327341
END;
328342

343+
/*
344+
╔══════════════════════════════════════════════════╗
345+
║ Single-use plans mode ║
346+
╚══════════════════════════════════════════════════╝
347+
348+
Shows the largest single-use plans by cached size,
349+
sorted by memory consumption descending.
350+
*/
351+
IF @find_single_use_plans = 1
352+
BEGIN
353+
SELECT TOP (@top)
354+
database_name =
355+
DB_NAME(CONVERT(integer, pa.value)),
356+
cached_plan_size_kb =
357+
cp.size_in_bytes / 1024,
358+
query_text =
359+
st.text,
360+
query_plan =
361+
CASE
362+
WHEN TRY_CAST(qp.query_plan AS xml) IS NOT NULL
363+
THEN TRY_CAST(qp.query_plan AS xml)
364+
WHEN TRY_CAST(qp.query_plan AS xml) IS NULL
365+
THEN
366+
(
367+
SELECT
368+
[processing-instruction(query_plan)] =
369+
N'-- ' + NCHAR(13) + NCHAR(10) +
370+
N'-- This is a huge query plan.' + NCHAR(13) + NCHAR(10) +
371+
N'-- Remove the headers and footers, save it as a .sqlplan file, and re-open it.' + NCHAR(13) + NCHAR(10) +
372+
NCHAR(13) + NCHAR(10) +
373+
REPLACE(qp.query_plan, N'<RelOp', NCHAR(13) + NCHAR(10) + N'<RelOp') +
374+
NCHAR(13) + NCHAR(10) COLLATE Latin1_General_Bin2
375+
FOR
376+
XML
377+
PATH(N''),
378+
TYPE
379+
)
380+
END,
381+
qs.query_hash,
382+
qs.query_plan_hash,
383+
qs.creation_time,
384+
qs.last_execution_time,
385+
qs.sql_handle,
386+
qs.plan_handle
387+
FROM sys.dm_exec_query_stats AS qs
388+
JOIN sys.dm_exec_cached_plans AS cp
389+
ON cp.plan_handle = qs.plan_handle
390+
CROSS APPLY
391+
(
392+
SELECT TOP (1)
393+
value = pa.value
394+
FROM sys.dm_exec_plan_attributes(qs.plan_handle) AS pa
395+
WHERE pa.attribute = N'dbid'
396+
) AS pa
397+
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
398+
OUTER APPLY sys.dm_exec_text_query_plan
399+
(
400+
qs.plan_handle,
401+
qs.statement_start_offset,
402+
qs.statement_end_offset
403+
) AS qp
404+
WHERE qs.execution_count = 1
405+
AND (@ignore_system_databases = 0 OR ISNULL(CONVERT(integer, pa.value), 0) NOT IN (1, 2, 3, 4))
406+
AND ISNULL(CONVERT(integer, pa.value), 0) < 32761
407+
AND (@database_id IS NULL OR CONVERT(integer, pa.value) = @database_id)
408+
ORDER BY
409+
cp.size_in_bytes DESC
410+
OPTION(RECOMPILE, MAXDOP 1);
411+
412+
RETURN;
413+
END;
414+
415+
/*
416+
╔══════════════════════════════════════════════════╗
417+
║ Duplicate plans mode ║
418+
╚══════════════════════════════════════════════════╝
419+
420+
Shows query hashes that have been compiled into
421+
multiple cached plans, sorted by plan count descending.
422+
*/
423+
IF @find_duplicate_plans = 1
424+
BEGIN
425+
SELECT TOP (@top)
426+
database_name =
427+
DB_NAME(CONVERT(integer, MAX(pa.value))),
428+
qs.query_hash,
429+
plan_count =
430+
COUNT_BIG(DISTINCT qs.plan_handle),
431+
total_executions =
432+
SUM(qs.execution_count),
433+
total_cpu_ms =
434+
SUM(qs.total_worker_time) / 1000.0,
435+
total_logical_reads =
436+
SUM(qs.total_logical_reads),
437+
total_cached_size_kb =
438+
SUM(cp.size_in_bytes) / 1024,
439+
oldest_plan =
440+
MIN(qs.creation_time),
441+
newest_plan =
442+
MAX(qs.creation_time),
443+
sample_query_text =
444+
MAX(st.text)
445+
FROM sys.dm_exec_query_stats AS qs
446+
JOIN sys.dm_exec_cached_plans AS cp
447+
ON cp.plan_handle = qs.plan_handle
448+
CROSS APPLY
449+
(
450+
SELECT TOP (1)
451+
value = pa.value
452+
FROM sys.dm_exec_plan_attributes(qs.plan_handle) AS pa
453+
WHERE pa.attribute = N'dbid'
454+
) AS pa
455+
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
456+
WHERE qs.query_hash <> 0x0000000000000000
457+
AND (@ignore_system_databases = 0 OR ISNULL(CONVERT(integer, pa.value), 0) NOT IN (1, 2, 3, 4))
458+
AND ISNULL(CONVERT(integer, pa.value), 0) < 32761
459+
AND (@database_id IS NULL OR CONVERT(integer, pa.value) = @database_id)
460+
GROUP BY
461+
qs.query_hash
462+
HAVING
463+
COUNT_BIG(DISTINCT qs.plan_handle) > 1
464+
ORDER BY
465+
COUNT_BIG(DISTINCT qs.plan_handle) DESC
466+
OPTION(RECOMPILE, MAXDOP 1);
467+
468+
RETURN;
469+
END;
470+
329471
/*
330472
╔══════════════════════════════════════════════════╗
331473
║ Plan cache health analysis ║
@@ -537,7 +679,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
537679
WHERE pa.attribute = N'dbid'
538680
) AS pa
539681
WHERE pa.value IS NOT NULL
540-
AND CONVERT(integer, pa.value) NOT IN (1, 2, 3, 4)
682+
AND (@ignore_system_databases = 0 OR CONVERT(integer, pa.value) NOT IN (1, 2, 3, 4))
541683
AND CONVERT(integer, pa.value) < 32761
542684
AND (@database_id IS NULL OR CONVERT(integer, pa.value) = @database_id)
543685
GROUP BY
@@ -646,7 +788,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
646788
WHERE pa.attribute = N'dbid'
647789
) AS pa
648790
WHERE pa.value IS NOT NULL
649-
AND CONVERT(integer, pa.value) NOT IN (1, 2, 3, 4)
791+
AND (@ignore_system_databases = 0 OR CONVERT(integer, pa.value) NOT IN (1, 2, 3, 4))
650792
AND CONVERT(integer, pa.value) < 32761
651793
AND (@database_id IS NULL OR CONVERT(integer, pa.value) = @database_id)
652794
GROUP BY

0 commit comments

Comments
 (0)