Skip to content

Commit 5615021

Browse files
Expand Rule 3 to cover all NonParallelPlanReason values
Adds human-readable messages for all 25 known reasons. Severity: - Warning: actionable reasons (UDFs, cursors, table variables, remote queries, trace flags, hints, DML OUTPUT, writeback variables) - Info: passive/environmental (cost below threshold, edition limits, memory-optimized tables, upgrade mode, index build edge cases) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a96b465 commit 5615021

1 file changed

Lines changed: 53 additions & 5 deletions

File tree

src/PlanViewer.Core/Services/PlanAnalyzer.cs

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,18 +133,66 @@ private static void AnalyzeStatement(PlanStatement stmt, AnalyzerConfig cfg)
133133
{
134134
var reason = stmt.NonParallelPlanReason switch
135135
{
136+
// User/config forced serial
136137
"MaxDOPSetToOne" => "MAXDOP is set to 1",
138+
"QueryHintNoParallelSet" => "OPTION (MAXDOP 1) hint forces serial execution",
139+
"ParallelismDisabledByTraceFlag" => "Parallelism disabled by trace flag",
140+
141+
// Passive — optimizer chose serial, nothing wrong
137142
"EstimatedDOPIsOne" => "Estimated DOP is 1 (the plan's estimated cost was below the cost threshold for parallelism)",
143+
144+
// Edition/environment limitations
138145
"NoParallelPlansInDesktopOrExpressEdition" => "Express/Desktop edition does not support parallelism",
146+
"NoParallelCreateIndexInNonEnterpriseEdition" => "Parallel index creation requires Enterprise edition",
147+
"NoParallelPlansDuringUpgrade" => "Parallel plans disabled during upgrade",
148+
"NoParallelForPDWCompilation" => "Parallel plans not supported for PDW compilation",
149+
"NoParallelForCloudDBReplication" => "Parallel plans not supported during cloud DB replication",
150+
151+
// Query constructs that block parallelism (actionable)
139152
"CouldNotGenerateValidParallelPlan" => "Optimizer could not generate a valid parallel plan. Common causes: scalar UDFs, inserts into table variables, certain system functions, or OPTION (MAXDOP 1) hints",
140-
"QueryHintNoParallelSet" => "OPTION (MAXDOP 1) hint forces serial execution",
153+
"TSQLUserDefinedFunctionsNotParallelizable" => "T-SQL scalar UDF prevents parallelism. Rewrite as an inline table-valued function, or on SQL Server 2019+ check if the UDF is eligible for automatic inlining",
154+
"CLRUserDefinedFunctionRequiresDataAccess" => "CLR UDF with data access prevents parallelism",
155+
"NonParallelizableIntrinsicFunction" => "Non-parallelizable intrinsic function in the query",
156+
"TableVariableTransactionsDoNotSupportParallelNestedTransaction" => "Table variable transaction prevents parallelism. Consider using a #temp table instead",
157+
"UpdatingWritebackVariable" => "Updating a writeback variable prevents parallelism",
158+
"DMLQueryReturnsOutputToClient" => "DML with OUTPUT clause returning results to client prevents parallelism",
159+
"MixedSerialAndParallelOnlineIndexBuildNotSupported" => "Mixed serial/parallel online index build not supported",
160+
"NoRangesResumableCreate" => "Resumable index create cannot use parallelism for this operation",
161+
162+
// Cursor limitations
163+
"NoParallelCursorFetchByBookmark" => "Cursor fetch by bookmark cannot use parallelism",
164+
"NoParallelDynamicCursor" => "Dynamic cursors cannot use parallelism",
165+
"NoParallelFastForwardCursor" => "Fast-forward cursors cannot use parallelism",
166+
167+
// Memory-optimized / natively compiled
168+
"NoParallelForMemoryOptimizedTables" => "Memory-optimized tables do not support parallel plans",
169+
"NoParallelForDmlOnMemoryOptimizedTable" => "DML on memory-optimized tables cannot use parallelism",
170+
"NoParallelForNativelyCompiledModule" => "Natively compiled modules do not support parallelism",
171+
172+
// Remote queries
173+
"NoParallelWithRemoteQuery" => "Remote queries cannot use parallelism",
174+
"NoRemoteParallelismForMatrix" => "Remote parallelism not available for this query shape",
175+
141176
_ => stmt.NonParallelPlanReason
142177
};
143178

144-
// Warn when the user forced serial or something in the query blocks parallelism.
145-
// Info only for passive reasons (cost below threshold, edition limitation).
146-
var isActionable = stmt.NonParallelPlanReason is "MaxDOPSetToOne"
147-
or "QueryHintNoParallelSet" or "CouldNotGenerateValidParallelPlan";
179+
// Actionable: user forced serial, or something in the query blocks parallelism
180+
// that could potentially be rewritten. Info: passive (cost too low) or
181+
// environmental (edition, upgrade, cursor type, memory-optimized).
182+
var isActionable = stmt.NonParallelPlanReason is
183+
"MaxDOPSetToOne" or "QueryHintNoParallelSet" or "ParallelismDisabledByTraceFlag"
184+
or "CouldNotGenerateValidParallelPlan"
185+
or "TSQLUserDefinedFunctionsNotParallelizable"
186+
or "CLRUserDefinedFunctionRequiresDataAccess"
187+
or "NonParallelizableIntrinsicFunction"
188+
or "TableVariableTransactionsDoNotSupportParallelNestedTransaction"
189+
or "UpdatingWritebackVariable"
190+
or "DMLQueryReturnsOutputToClient"
191+
or "NoParallelCursorFetchByBookmark"
192+
or "NoParallelDynamicCursor"
193+
or "NoParallelFastForwardCursor"
194+
or "NoParallelWithRemoteQuery"
195+
or "NoRemoteParallelismForMatrix";
148196

149197
stmt.PlanWarnings.Add(new PlanWarning
150198
{

0 commit comments

Comments
 (0)