Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/PlanViewer.App/PlanViewer.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>EDD.ico</ApplicationIcon>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
<Version>1.4.1</Version>
<Version>1.4.2</Version>
<Authors>Erik Darling</Authors>
<Company>Darling Data LLC</Company>
<Product>Performance Studio</Product>
Expand Down
58 changes: 54 additions & 4 deletions src/PlanViewer.Core/Services/PlanAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,22 +133,72 @@
{
var reason = stmt.NonParallelPlanReason switch
{
// User/config forced serial
"MaxDOPSetToOne" => "MAXDOP is set to 1",
"QueryHintNoParallelSet" => "OPTION (MAXDOP 1) hint forces serial execution",
"ParallelismDisabledByTraceFlag" => "Parallelism disabled by trace flag",

// Passive — optimizer chose serial, nothing wrong
"EstimatedDOPIsOne" => "Estimated DOP is 1 (the plan's estimated cost was below the cost threshold for parallelism)",

// Edition/environment limitations
"NoParallelPlansInDesktopOrExpressEdition" => "Express/Desktop edition does not support parallelism",
"NoParallelCreateIndexInNonEnterpriseEdition" => "Parallel index creation requires Enterprise edition",
"NoParallelPlansDuringUpgrade" => "Parallel plans disabled during upgrade",
"NoParallelForPDWCompilation" => "Parallel plans not supported for PDW compilation",
"NoParallelForCloudDBReplication" => "Parallel plans not supported during cloud DB replication",

// Query constructs that block parallelism (actionable)
"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",
"QueryHintNoParallelSet" => "OPTION (MAXDOP 1) hint forces serial execution",
"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",
"CLRUserDefinedFunctionRequiresDataAccess" => "CLR UDF with data access prevents parallelism",
"NonParallelizableIntrinsicFunction" => "Non-parallelizable intrinsic function in the query",
"TableVariableTransactionsDoNotSupportParallelNestedTransaction" => "Table variable transaction prevents parallelism. Consider using a #temp table instead",
"UpdatingWritebackVariable" => "Updating a writeback variable prevents parallelism",
"DMLQueryReturnsOutputToClient" => "DML with OUTPUT clause returning results to client prevents parallelism",
"MixedSerialAndParallelOnlineIndexBuildNotSupported" => "Mixed serial/parallel online index build not supported",
"NoRangesResumableCreate" => "Resumable index create cannot use parallelism for this operation",

// Cursor limitations
"NoParallelCursorFetchByBookmark" => "Cursor fetch by bookmark cannot use parallelism",
"NoParallelDynamicCursor" => "Dynamic cursors cannot use parallelism",
"NoParallelFastForwardCursor" => "Fast-forward cursors cannot use parallelism",

// Memory-optimized / natively compiled
"NoParallelForMemoryOptimizedTables" => "Memory-optimized tables do not support parallel plans",
"NoParallelForDmlOnMemoryOptimizedTable" => "DML on memory-optimized tables cannot use parallelism",
"NoParallelForNativelyCompiledModule" => "Natively compiled modules do not support parallelism",

// Remote queries
"NoParallelWithRemoteQuery" => "Remote queries cannot use parallelism",
"NoRemoteParallelismForMatrix" => "Remote parallelism not available for this query shape",

_ => stmt.NonParallelPlanReason
};

// Only warn (not info) when the user explicitly forced serial execution
var isExplicit = stmt.NonParallelPlanReason is "MaxDOPSetToOne" or "QueryHintNoParallelSet";
// Actionable: user forced serial, or something in the query blocks parallelism
// that could potentially be rewritten. Info: passive (cost too low) or
// environmental (edition, upgrade, cursor type, memory-optimized).
var isActionable = stmt.NonParallelPlanReason is
"MaxDOPSetToOne" or "QueryHintNoParallelSet" or "ParallelismDisabledByTraceFlag"
or "CouldNotGenerateValidParallelPlan"
or "TSQLUserDefinedFunctionsNotParallelizable"
or "CLRUserDefinedFunctionRequiresDataAccess"
or "NonParallelizableIntrinsicFunction"
or "TableVariableTransactionsDoNotSupportParallelNestedTransaction"
or "UpdatingWritebackVariable"
or "DMLQueryReturnsOutputToClient"
or "NoParallelCursorFetchByBookmark"
or "NoParallelDynamicCursor"
or "NoParallelFastForwardCursor"
or "NoParallelWithRemoteQuery"
or "NoRemoteParallelismForMatrix";

stmt.PlanWarnings.Add(new PlanWarning
{
WarningType = "Serial Plan",
Message = $"Query running serially: {reason}.",
Severity = isExplicit ? PlanWarningSeverity.Warning : PlanWarningSeverity.Info
Severity = isActionable ? PlanWarningSeverity.Warning : PlanWarningSeverity.Info
});
}

Expand Down Expand Up @@ -984,7 +1034,7 @@
// Rule 28: Row Count Spool — NOT IN with nullable column
// Pattern: Row Count Spool with high rewinds, child scan has IS NULL predicate,
// and statement text contains NOT IN
if (!cfg.IsRuleDisabled(28) && node.PhysicalOp.Contains("Row Count Spool"))

Check warning on line 1037 in src/PlanViewer.Core/Services/PlanAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Dereference of a possibly null reference.

Check warning on line 1037 in src/PlanViewer.Core/Services/PlanAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Dereference of a possibly null reference.

Check warning on line 1037 in src/PlanViewer.Core/Services/PlanAnalyzer.cs

View workflow job for this annotation

GitHub Actions / release

Dereference of a possibly null reference.

Check warning on line 1037 in src/PlanViewer.Core/Services/PlanAnalyzer.cs

View workflow job for this annotation

GitHub Actions / release

Dereference of a possibly null reference.
{
var rewinds = node.HasActualStats ? (double)node.ActualRewinds : node.EstimateRewinds;
if (rewinds > 10000 && HasNotInPattern(node, stmt))
Expand Down
1 change: 1 addition & 0 deletions src/PlanViewer.Web/Pages/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<div class="landing-content">
<h2>Free SQL Server Query Plan Analysis</h2>
<p class="privacy">Paste or upload a .sqlplan file. Your plan XML never leaves your browser.</p>
<p class="powered-by">Powered by the same analysis engine in the <a href="https://github.com/erikdarlingdata/PerformanceStudio" target="_blank" rel="noopener">Performance Studio</a> app.</p>

@if (errorMessage != null)
{
Expand Down
16 changes: 16 additions & 0 deletions src/PlanViewer.Web/wwwroot/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,25 @@ main {
font-family: 'Montserrat', sans-serif;
font-size: 1.05rem;
font-weight: 600;
margin-bottom: 0.4rem;
}

.powered-by {
color: var(--text-secondary);
font-size: 0.9rem;
margin-bottom: 1.5rem;
}

.powered-by a {
color: var(--accent);
text-decoration: none;
font-weight: 600;
}

.powered-by a:hover {
text-decoration: underline;
}

/* === Input Area === */
.input-area {
text-align: left;
Expand Down
Binary file added src/PlanViewer.Web/wwwroot/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions src/PlanViewer.Web/wwwroot/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Free SQL Server Query Plan Analysis — Darling Data</title>
<meta name="description" content="Free browser-based SQL Server execution plan analysis. Paste or upload a .sqlplan file — your plan XML never leaves your browser." />
<meta property="og:title" content="Free SQL Server Query Plan Analysis" />
<meta property="og:description" content="Analyze SQL Server execution plans instantly in your browser. Paste or upload a .sqlplan file — nothing to install, no data sent to a server." />
<meta property="og:image" content="https://plans.erikdarling.com/darling-data-logo.jpg" />
<meta property="og:url" content="https://plans.erikdarling.com" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Free SQL Server Query Plan Analysis" />
<meta name="twitter:description" content="Analyze SQL Server execution plans instantly in your browser. Paste or upload a .sqlplan file — nothing to install, no data sent to a server." />
<meta name="twitter:image" content="https://plans.erikdarling.com/darling-data-logo.jpg" />
<link rel="icon" type="image/png" href="favicon.png" />
<base href="/" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
Expand Down
Loading