Skip to content

Commit 74d64a7

Browse files
sp_BlitzCache: return oversized plans inline instead of manual query fallback
Fixes #3868 — when a plan exceeds 128 levels of XML nesting, populate the QueryPlan column with the text plan wrapped in an XML processing instruction (same technique as sp_QuickieStore) instead of leaving it NULL and telling the user to run dm_exec_text_query_plan manually. Also uses StatementStartOffset/StatementEndOffset for statement-level plan retrieval, and separates truly missing plans into their own UPDATE. Tested on SQL2016, SQL2017, SQL2019, SQL2022, SQL2025. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2422c4b commit 74d64a7

1 file changed

Lines changed: 39 additions & 18 deletions

File tree

sp_BlitzCache.sql

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5077,25 +5077,46 @@ WHERE QueryType LIKE 'Procedure or Function%'
50775077
AND SPID = @@SPID
50785078
OPTION (RECOMPILE);
50795079

5080-
RAISERROR('Checking for plans with >128 levels of nesting', 0, 1) WITH NOWAIT;
5081-
WITH plan_handle AS (
5082-
SELECT b.PlanHandle
5083-
FROM ##BlitzCacheProcs b
5084-
CROSS APPLY sys.dm_exec_text_query_plan(b.PlanHandle, 0, -1) tqp
5085-
CROSS APPLY sys.dm_exec_query_plan(b.PlanHandle) qp
5086-
WHERE tqp.encrypted = 0
5087-
AND b.SPID = @@SPID
5088-
AND (qp.query_plan IS NULL
5089-
AND tqp.query_plan IS NOT NULL)
5090-
)
5091-
UPDATE b
5092-
SET Warnings = ISNULL('Your query plan is >128 levels of nested nodes, and can''t be converted to XML. Use SELECT * FROM sys.dm_exec_text_query_plan('+ CONVERT(VARCHAR(128), ph.PlanHandle, 1) + ', 0, -1) to get more information'
5093-
, 'We couldn''t find a plan for this query. More info on possible reasons: https://www.brentozar.com/go/noplans')
5094-
FROM ##BlitzCacheProcs b
5095-
LEFT JOIN plan_handle ph ON
5096-
b.PlanHandle = ph.PlanHandle
5080+
/* Populate oversized plans as processing instructions so they're clickable in SSMS */
5081+
RAISERROR('Checking for plans with >128 levels of nesting', 0, 1) WITH NOWAIT;
5082+
UPDATE
5083+
b
5084+
SET
5085+
b.QueryPlan =
5086+
(
5087+
SELECT
5088+
[processing-instruction(query_plan)] =
5089+
N'-- ' + NCHAR(13) + NCHAR(10) +
5090+
N'-- This is a huge query plan.' + NCHAR(13) + NCHAR(10) +
5091+
N'-- Remove the headers and footers, save it as a .sqlplan file, and re-open it.' + NCHAR(13) + NCHAR(10) +
5092+
NCHAR(13) + NCHAR(10) +
5093+
REPLACE(tqp.query_plan, N'<RelOp', NCHAR(13) + NCHAR(10) + N'<RelOp') +
5094+
NCHAR(13) + NCHAR(10)
5095+
FOR
5096+
XML
5097+
PATH(N''),
5098+
TYPE
5099+
),
5100+
b.Warnings = 'This is a huge query plan (>128 levels of nesting). Click the plan link, remove the headers and footers, and save it as a .sqlplan file to view it.'
5101+
FROM ##BlitzCacheProcs AS b
5102+
CROSS APPLY sys.dm_exec_text_query_plan(b.PlanHandle, b.StatementStartOffset, b.StatementEndOffset) AS tqp
5103+
CROSS APPLY sys.dm_exec_query_plan(b.PlanHandle) AS qp
50975104
WHERE b.QueryPlan IS NULL
5098-
AND b.SPID = @@SPID
5105+
AND b.SPID = @@SPID
5106+
AND tqp.encrypted = 0
5107+
AND qp.query_plan IS NULL
5108+
AND tqp.query_plan IS NOT NULL
5109+
OPTION (RECOMPILE);
5110+
5111+
/* Handle truly missing plans (encrypted, evicted, etc.) */
5112+
UPDATE
5113+
b
5114+
SET
5115+
b.Warnings = 'We couldn''t find a plan for this query. More info on possible reasons: https://www.brentozar.com/go/noplans'
5116+
FROM ##BlitzCacheProcs AS b
5117+
WHERE b.QueryPlan IS NULL
5118+
AND b.Warnings IS NULL
5119+
AND b.SPID = @@SPID
50995120
OPTION (RECOMPILE);
51005121

51015122
RAISERROR('Checking for plans with no warnings', 0, 1) WITH NOWAIT;

0 commit comments

Comments
 (0)