Skip to content

Latest commit

 

History

History
239 lines (183 loc) · 14.2 KB

File metadata and controls

239 lines (183 loc) · 14.2 KB

dbopt

dbopt

Find and fix slow SQL before it reaches production — statically, privately, prescriptively.

CI SQL lint latest release Apache-2.0 crates.io npm

Try it in your browser →  ·  Usage guide  ·  Who it's for  ·  Data handling  ·  Roadmap


dbopt is a database performance optimizer. Point it at a database and it reads your queries, your execution plans and your live server metrics — then tells you exactly what is going to hurt and how to fix it, with the reasoning cited. It works statically and from the estimated plan, so there is no execution, no locks, no load on production.

One tool, every database. dbopt is engine-agnostic from the core out: every rule declares which database it applies to, so engines are added without destabilizing each other. SQL Server (2014 → 2025) is live today with all 103 rules; PostgreSQL and MySQL are next. Ask for an engine whose rules haven't landed and you get an empty report — the analyzer would rather say nothing than guess.

Free and open. No per-seat cost, no paywalled features — what the commercial tools do, without monetizing your pain.

Try it without installing anything

Paste a query at dbopt.org and the analyzer runs in your browser — it is this repository's Rust engine compiled to WebAssembly, so your SQL never leaves the tab. The page measures and prints its own network activity while you use it, so you don't have to take that on faith.

Install

# Linux & macOS (Apple Silicon)
curl -fsSL https://dbopt.org/install.sh | sh
# Windows (PowerShell)
irm https://dbopt.org/install.ps1 | iex
Platform Download
Windows (x64) .msi · portable .zip
macOS (Apple Silicon) .dmg
Linux (x64) .tar.gz (glibc 2.34+) · static musl (Alpine, RHEL 8, any distro)

Each is a single self-contained binary with the web UI embedded — run it, then open http://127.0.0.1:3690. Checksums are on the releases page.

Each archive contains two binaries: dbopt (the linter — dbopt lint ./db, offline, no connection needed) and dbopt-backend (the local app — run it and open http://127.0.0.1:3690). A WHICH-BINARY.txt in the archive says the same thing.

Developers can skip the installer entirely:

cargo install dbopt     # the CLI + linter
npm i dbopt-core        # the analyzer in Node or the browser

First run: the builds are not code-signed yet, so the OS warns you once. Windows — More info → Run anyway. macOS — right-click → Open, or xattr -dr com.apple.quarantine /Applications/dbopt.app. Linux has no prompt. Signing is on the roadmap.

Lint your SQL in CI — offline, no connection

dbopt lint walks your .sql files, applies all 103 rules and emits machine-readable output, so a bad query fails the build before it ships.

dbopt lint ./db --format human               # grouped by file (default)
dbopt lint ./db --format json                # machine-readable findings
dbopt lint ./db --format sarif > dbopt.sarif # SARIF 2.1.0 for code scanning
dbopt lint ./db --fail-on warning            # exit 1 to gate a pull request
dbopt lint ./db --ignore hygiene.nolock      # silence a rule (or a family, or a glob)
dbopt lint --stdin                           # lint a query on stdin

Exit codes: 0 clean · 1 findings at/above --fail-on (default error) · 2 usage error or an input that could not be read.

Silence a rule with --ignore, or in the SQL itself — -- dbopt-ignore-file, -- dbopt-ignore-next-line, or a trailing -- dbopt-ignore <rules>. Suppressed findings are counted in the summary, so an ignore-riddled file cannot quietly look clean.

- run: dbopt lint ./db --format sarif > dbopt.sarif
  continue-on-error: true      # still upload the report when the gate trips
- uses: github/codeql-action/upload-sarif@v3
  with: { sarif_file: dbopt.sarif }
- run: dbopt lint ./db --fail-on error   # the gate itself

Findings then appear inline on the PR diff. The SARIF also opens in the VS Code SARIF Viewer, and there is a pre-commit hook that blocks a commit on error-level findings.

Three lenses, one tool

Lens What it does
01 Static A token-level analyzer — 103 rules across sargability, index design, plan shape, hygiene, modern rewrites, locking, tempdb, statistics, transactions, security and datatypes. Runs in-browser via WebAssembly or as a CLI. No connection required.
02 Plan Fetches the estimated plan (compile-only — never runs the query) and breaks down operator cost, scans vs. seeks, spill and lookup risk.
03 Live Reads index usage, missing indexes and sizes on demand; the sentinel daemon samples query history, waits, deadlocks and vitals into a local SQLite time-series, with thresholds and webhook alerts.

Every finding carries a severity, the offending line, a copy-paste rewrite and the engine-level reasoning behind it. Advice is version-gated — a 2022+ rewrite is never suggested against a 2019 target.

Where it sits

Free DBA scripts Commercial monitors dbopt
Cost Free Per-instance licence Free & open
Works with no connection No No Yes — static + plan
Catches it before it runs No No Yes
Tells you what to type Some advice Metrics, rarely fixes Rewrite + reason
Your data leaves the box Never Often a hosted service Never, unless you pick a cloud model
Runs in CI No No SARIF, exit codes
Cross-platform GUI Vendor-tool bound Windows-centric Linux, macOS, Windows

dbopt is the only one of the three that can tell you a query is wrong before it has ever run — and the only one that does it without your queries leaving the building.

Local-first and private

A single Rust binary with SQLite for storage. dbopt reads catalog views, dynamic management views and query history — metadata, never your table rows. Estimated plans are compile-only and DDL is preview-only; Safe-Apply never runs a change for you.

AI is your call. Run a local model (Ollama / web-llm) and nothing leaves the machine. Prefer a frontier model? Pick a cloud provider (Anthropic, OpenAI, Azure OpenAI, OpenRouter) and only your prompt — the SQL plus its findings — is sent, and only when you choose it. Beyond that, the installed app makes one optional anonymous version check to GitHub, which you can switch off. That is the complete list; see docs/DATA-HANDLING.md. (AWS Bedrock also works, but only in a source build with the bedrock feature — it is not in the prebuilt downloads.)

Quality bar

  • 312 eval scenarios · precision = recall = F1 = 1.000. CI fails if any scenario fails, and separately if F1 drops below 0.95 — an aggregate alone would let a localized regression through. The harness is self-graded — the scenarios are hand-authored, so this proves no regression on the cases we wrote, not a measured real-world false-positive rate. That is what the held-out corpus below is for.
  • Every one of the 104 rule ids has a scenario — a positive case (proves it fires) and a negative case (proves it stays quiet on similar-looking benign SQL). A further 13 scenarios cover the 12 plan-XML and DMV checks.
  • Held-out validation (false positives). The self-graded F1 above cannot measure a real false-positive rate — the same people write the rules and the tests. So the analyzer is also run over 71,758 lines of third-party production T-SQL we did not write, across two deliberately different distributions: DBA tooling (Ola Hallengren's Maintenance Solution; sp_Blitz, sp_BlitzIndex, sp_BlitzCache) and application schemas (AdventureWorks, Northwind, Pubs, Chinook), which fail in different ways. Every finding at error severity or above is classified by hand: currently 143 high-severity findings. Reproduce with ./tools/heldout-corpus.sh.
  • Seeded-defect recall (false negatives). A corpus of real code can only measure false positives — you cannot count what a linter failed to say. So ./tools/seeded-defects.py plants defects whose rule is known by construction into that same real code, at validated statement positions and behind deliberately hostile preceding context (a missing semicolon, SET NOCOUNT ON, an identifier that spells a keyword, a closed multi-line literal), and checks each is reported on its own line: 4,050 injected, recall 1.000.
  • How much to trust those two numbers. Not blindly. They are our own classification of our own tool, and an independent adversarial review disputed 17 of a previous run's 161 high-severity findings — 12 false positives on projections and 5 that flagged the string 'xp_cmdshell' in code merely checking whether it was enabled. All 17 are fixed and pinned by scenarios, which is why the number moved down. Assume the next review finds more.
  • Rust unit + HTTP integration tests, and a Playwright UI suite.
cargo run -p eval -- --html   # → target/eval-report.html

Engines

Engine Status Notes
SQL Server Live 2014 → 2025 · all 103 rules
PostgreSQL Next engine seam wired · rules coming
MySQL Next engine seam wired · rules coming

The Engine seam runs end to end — AnalyzeInputanalyze()rules::run_all — and every rule declares the engines it applies to, so each new database plugs in behind the same API, UI and report without touching the ones already shipping. See docs/ROADMAP.md.

Architecture

A Rust workspace plus a React / Vite / TypeScript front end:

Crate Role
dbopt-core the rule engine, tokenizer and plan / metric models (dir: crates/analyzer-core)
dbopt the CLI — lint a tree, or analyze a .sql / .sqlplan / bundle (dir: crates/analyzer-cli)
analyzer-wasm WebAssembly bindings for in-browser and Node analysis
backend dbopt-backend — axum API + embedded web UI, LLM proxy, durable logs
sentinel dbopt-sentinel — continuous poller → SQLite → pain report, alerts
eval the rule-quality harness (precision / recall / F1 + HTML report)
web/ the "observatory" UI (analysis, plans, charts, AI, monitoring)

Storage and config live under ~/.dbopt/ (override with DBOPT_DATA_DIR). No external services required.

Build from source

You'll need Rust, Node 18+ and wasm-pack:

# The web UI is embedded into the backend binary at compile time, so build it first.
wasm-pack build crates/analyzer-wasm --target web --out-dir ../../web/src/wasm --release
cd web && npm install && npm run build && cd ..

cargo build --release

./target/release/dbopt path/to/query.sql   # analyze a script, no connection needed
./target/release/dbopt-backend             # the web UI + API on :3690

DBOPT_SERVER="host,1433" DBOPT_USER="..." DBOPT_PASSWORD="..." \
  ./target/release/dbopt-sentinel run      # continuous monitoring

For UI work: cd web && npm run dev (proxies the API to the backend on :3690). Contributions — especially new rules — are covered in CONTRIBUTING.md.

Authentication

SQL Server authentication (username + password) works out of the box, and Windows builds support integrated Windows auth. For Kerberos on Linux, rebuild with the integrated-auth feature:

cargo build --release -p backend  --features integrated-auth
cargo build --release -p sentinel --features integrated-auth

It is off by default because those system libraries aren't on every build host.


Local-first by design — your queries, schema and metrics stay on your infrastructure.
dbopt.org
© 2026 Prateek Singh