SQL Refactor Analyzer is a Windows desktop tool that scans stored procedures, views, and functions — across a live database or a folder of .sql files — for anti-patterns and deprecated syntax, then correlates that with real execution-plan and index data from the DMVs. It draws the execution plan as a colour-coded operator tree, ranks your worst objects into a dedicated Problem-Queries view, and generates ready-to-use fixes. It is strictly read-only: it only ever runs SELECT against system catalog views, never ALTER/CREATE/DROP, and never writes back to a scanned file.
Turning a vague complaint into a prioritised list of concrete changes usually means hand-writing DMV queries, reading plan XML by eye, and knowing which anti-patterns to grep for. This tool does all three at once and hands you the shortlist.
| Without it | With SQL Refactor Analyzer |
|---|---|
| Anti-patterns found only when someone happens to read the code | Every module scanned against 14 rules in one pass |
| Plan XML read by eye, warning by warning | A colour-coded operator tree with the decisive problems highlighted |
| "Missing index" hints copied out of SSMS one at a time | Generated CREATE INDEX statements, ranked by impact |
| No sense of which object is actually the worst | A Problem-Queries view ranking objects by severity & impact |
| No way to prove last month's cleanup actually helped | Baseline compare: new / fixed / unchanged since a saved scan |
| Operating system | Windows 10, Windows 11, or Windows Server 2019 or later |
| Runtime | .NET Framework 4.8 — ships with Windows, nothing to install on a target DBA workstation or jump host |
| SQL Server | 2016 or later for the live-database and Query Store features; the static .sql folder scan needs no SQL Server at all |
| Access | A login that can read the DMVs and catalog views — no elevated rights, no writes |
| Dependency | Microsoft.Data.SqlClient — used only for live-database connections |
This is a standalone Windows desktop application, not a PowerShell module — it doesn't need dbatools or PowerShell to run. It's a native rewrite of the earlier PowerShell sqmRefactorTool wizard, built by the same author as the rest of this toolchain.
Each rule scans the T-SQL token stream — a dependency-free tokenizer, not a full parser — for a specific, well-understood problem. Anti-patterns (AP) and formatting rules (FMT) run offline on a folder of .sql files as happily as they do against a live database.
| Rule | Severity | What it flags |
|---|---|---|
| AP001 | Warning | SELECT * instead of an explicit column list |
| AP002 | Warning | WITH (NOLOCK) table hint |
| AP003 | Warning | Cursor instead of set-based processing |
| AP004 | Warning | Likely scalar UDF call in a WHERE/JOIN predicate |
| AP005 | Critical | Dynamic SQL built via string concatenation in EXEC() |
| AP006 | Info | User procedure named with the reserved sp_ prefix |
| AP007 | Info | Table reference without an explicit schema prefix |
| AP008 | Critical | Deprecated *=/=* outer-join syntax |
| AP009 | Critical | UPDATE/DELETE without a WHERE clause |
| AP010 | Warning | Function on a column in a predicate (YEAR(col) = ...) — non-SARGable |
| AP011 | Warning | NOT IN with a subquery — one NULL silently empties the result |
| AP012 | Warning | SELECT TOP n without ORDER BY — nondeterministic |
| AP013 | Warning | Leading-wildcard LIKE '%...' — non-SARGable, forces a scan |
| AP014 | Warning | Arithmetic or concatenation on a column in a predicate (Col + 1 = ...) — non-SARGable |
| FMT001 | Info | Missing SET NOCOUNT ON |
| FMT002 | Info | Inconsistent keyword casing |
Findings export to a self-contained dark-theme HTML report or to Markdown, both led by a prioritised "Action Items" list — the highest-severity, highest-impact findings across every rule, first.
Against a live database, the tool reads cached plans and index DMVs and turns them into findings — no plan XML to decode by hand.
| Check | What it surfaces |
|---|---|
| QP001 | Plan-cache warnings with a plain-language root cause — spills to tempdb, implicit conversions, missing statistics, cross joins with no predicate |
| QP002–004 | Unused, duplicate/overlapping, and disabled indexes |
| QP005 | Plan overview: degree of parallelism vs. the server's real cost threshold for parallelism, and memory-grant efficiency |
| QP006 | The most expensive operators per statement, by estimated subtree cost |
| QP007 | Cardinality mismatch: estimated vs. actual average row count, sorted by severity, with likely root causes |
| QP008 | DBA heuristics: skewed hash/merge-join inputs and per-thread parallelism skew |
| QP009 | Missing-index suggestions with a generated, ready-to-use CREATE INDEX statement |
These rely on the plan cache and DMVs, so they reflect what has actually run recently — read-only, and honest about their limits: a cached plan holds compile-time estimates, and where a value only exists in an actual plan the tool says so rather than guessing.
Double-click any query-plan finding to open the execution plan as a graphical operator tree. Box colour is a cost heat map; edge thickness scales with estimated row count — the same "fat pipe" idea SSMS uses. But cost only tells you what's expensive, not what's broken, so decisive problems get their own fixed highlight: an operator with a critical plan warning (a tempdb spill, a cross join with no predicate) is drawn solid red no matter how cheap it looks, and lesser warnings get an amber border. A cheap-but-broken operator can't hide next to an expensive-but-fine one.
When a plan has been evicted from the cache, the visualizer falls back to Query Store automatically — so plans survive restarts and eviction — and the window title tells you which source it used. You can save any statement's plan as a .sqlplan file for full-detail viewing in SSMS or Azure Data Studio, and open a .sqlplan a colleague sends you completely offline.
A flat findings list doesn't tell you where to start. The Problem-Queries tab groups every finding by object and ranks them by a severity- and impact-weighted score — an object racking up a SELECT *, a cursor, a cardinality mismatch, and a missing index is empirically a worse query than one with a single formatting nit, and this surfaces that automatically. Select a row to see every finding for that object, plus any ready-to-use improvement suggestion (like QP009's generated CREATE INDEX). It's a different lens on the same scan, not a second engine.
Save the current findings as a JSON baseline, then compare a later scan against it: new, fixed, and unchanged since the baseline. For recurring engagements on the same database, that turns the report from a snapshot into a progress record. The comparison ignores the volatile numbers embedded in plan messages, so it doesn't report the same problem as both fixed and new every run. Available in the GUI and headless for CI.
The same engine that drives the GUI is available from the command line — for gating a build on new anti-patterns, or generating a report as a pipeline artifact.
SqlRefactorAnalyzer.exe --scanfolder <folder> [--savebaseline <file.json>] # Scan *.sql, optionally save a baseline SqlRefactorAnalyzer.exe --scanfolder <folder> --comparebaseline <file.json> # Diff against an earlier baseline SqlRefactorAnalyzer.exe --report <folder> html|md <outfile> # Scan + write a report SqlRefactorAnalyzer.exe --dbscan <server> <database> [--plananalysis] # Live scan incl. plan/index analysis
Every database interaction is a SELECT against a catalog view or DMV. The tool never issues DDL or DML, never modifies a scanned .sql file, and never stores a password — SQL-authenticated connections re-enter the password each session.
Target machines are DBA workstations and jump hosts that don't reliably have a modern .NET desktop runtime. .NET Framework 4.8 ships with Windows, so deployment is a folder copy — no installer, no runtime prerequisite. A GitHub Actions workflow packages the ready-to-run build as a ZIP on every release tag.
Rules scan a flat token stream rather than a full T-SQL parse tree — a documented trade-off shared with the rest of this toolchain. It keeps the tool dependency-free and fast; the edge cases where a token scan can mis-bound a clause are documented per rule, not swept under the rug.
The offline folder scan needs nothing but the executable; the plan analysis and visualizer add value the moment you connect to a live instance.
A Windows executable — copy the folder, run the exe. No installer, no separate .NET runtime, read-only against your databases.
The companion desktop tool for SSIS projects: audit packages, compare versions, and map data lineage before you deploy.
Get in touch about the tool, a feature, or the wider powershelldba.de toolchain.