The tools that exist for SQL performance are built for DBAs. They cost $400/month, require installing an agent with database credentials, and assume you already know what an execution plan is and what to do with it.
That leaves a gap. Most development teams — especially startups, small engineering teams, and solo developers — don't have a dedicated DBA. When a query is slow, the developer who wrote it is also the person who has to fix it. And the tools available to them are either a generic LLM that doesn't know which database they're on, or an enterprise product they can't afford or access.
I built QueryTuner for that gap.
What it does
Paste a SQL query. Select your database dialect.
Get back in under a second:
- What's wrong and why — specific patterns causing performance problems, explained in plain English
- A rewritten query — with slow patterns fixed, dialect-correct syntax
- The exact index to create — for your specific database, not generic advice
- A security scan — SQL injection risk patterns
- A shareable report URL — permanent link to the analysis for PR comments or Slack threads
No database connection. No credentials. No installation.
Why no database connection
This was a deliberate architecture decision, not a limitation.
Every enterprise SQL diagnostic tool requires database credentials. That means a security review before you can even try the tool. In most organizations that review takes longer than fixing the query.
QueryTuner analyzes query syntax and structure. You paste the SQL text — the same text you already have in your editor. No connection string, no firewall rules, no credential approval process.
The tradeoff: without connecting to your database, QueryTuner can't know actual table sizes, row counts, or current index usage. Recommendations are marked estimated unless you provide schema DDL — more on that below.
The dialect problem
SQL is not one language. The correct way to create an index in production differs significantly across databases:
-- PostgreSQL (CONCURRENTLY avoids locking the table)
CREATE INDEX CONCURRENTLY idx_orders_customer_id
ON orders(customer_id);
-- MySQL (ALTER TABLE is the idiomatic form)
ALTER TABLE orders ADD INDEX
idx_orders_customer_id (customer_id);
-- Oracle (NOLOGGING skips redo log for faster creation)
CREATE INDEX idx_orders_customer_id
ON orders(customer_id) NOLOGGING;
-- SQL Server (ONLINE=ON allows reads/writes during build)
CREATE NONCLUSTERED INDEX idx_orders_customer_id
ON orders(customer_id) WITH (ONLINE=ON, FILLFACTOR=90);
-- SQLite (no concurrent DDL — locks the database file)
CREATE INDEX IF NOT EXISTS idx_orders_customer_id
ON orders(customer_id);
Generic advice ("add an index on customer_id") is not enough. The DDL you run in production depends on your database. QueryTuner generates the correct statement for whichever of the five supported dialects you select.
What it catches
12 heuristic rules, always running in under 5ms:
High severity:
- Functions on indexed columns in WHERE clauses —
YEAR(created_at) = 2024forces a full table scan. Rewrite ascreated_at BETWEEN '2024-01-01' AND '2024-12-31'and the index works again. - Correlated subqueries in the SELECT clause — executes once per row of the outer query. On 10,000 rows that's 10,000 separate lookups. A LEFT JOIN is evaluated once.
- Cartesian JOINs — a JOIN without an ON clause multiplies every row in table A by every row in table B. On production tables this can return millions of rows and crash your database.
- Leading wildcard LIKE patterns —
LIKE '%value'cannot use a B-tree index. Full table scan every time.
Medium severity:
- SELECT * fetching unnecessary columns
- ORDER BY without LIMIT on large result sets
- Implicit type casts preventing index use
- Missing indexes on JOIN keys, WHERE filters, ORDER BY, GROUP BY columns
Schema-aware confirmed recommendations
The tool works without schema information. But if you paste your CREATE TABLE statements alongside the query, recommendations upgrade from
estimated to confirmed.
Without schema:
ddl_hint: "CREATE INDEX idx_o_customer_id
ON <o_table>(customer_id)"
confirmed: false
With schema:
ddl_hint: "CREATE INDEX CONCURRENTLY
idx_orders_customer_id
ON orders(customer_id)"
confirmed: true
With schema provided, QueryTuner:
- Resolves table aliases to real table names
- Verifies the column actually exists
- Suppresses suggestions for indexes already in your DDL
- Generates copy-pasteable DDL with your real table names
The LLM layer
When enabled, an optional LLM layer (HuggingFace or OpenAI) adds narrative context on top of the heuristic findings — plain-English diagnosis, a rewritten query using CTEs, and flags for assumptions it can't verify without schema.
The heuristic layer always runs regardless. If the LLM fails (cold start, rate limit), the structured findings are still returned. The LLM is additive, not load-bearing.
Try it
Live: querytuner.com
Source: github.com/AutoShiftOps/querytuner
API example — paste query + schema, get confirmed DDL:
curl -X POST \
https://sql-query-analyzer-ekbk.onrender.com/analyze \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT u.id, u.name, o.total FROM users u JOIN orders o ON o.customer_id = u.id WHERE u.status = '\''active'\'' ORDER BY o.created_at DESC",
"db_type": "postgresql",
"use_llm": false,
"schema_info": "CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT NOT NULL, status VARCHAR(20));\nCREATE TABLE orders (id SERIAL PRIMARY KEY, customer_id INTEGER NOT NULL, total NUMERIC(10,2), created_at TIMESTAMPTZ DEFAULT NOW());"
}'
Response includes:
{
"optimization_suggestions": [
{
"type": "index_review_join_key",
"severity": "high",
"suggestion": "JOIN key o.customer_id may lack an index",
"ddl_hint": "CREATE INDEX CONCURRENTLY idx_orders_customer_id ON orders(customer_id);",
"ddl_note": "Use CONCURRENTLY to avoid locking the table in production.",
"confirmed": true
}
],
"plain_explanation": "## Schema Context\n- QueryTuner cross-referenced 3/4 suggestions against schema — 3 confirmed, 1 estimated",
"share_url": "https://querytuner.com/report/11ac926d-89a9-4e52-ad9c-d14c70d37965"
}
confirmed: true means the column exists in your schema, no index on it appears in your DDL, and the DDL uses your real table name — not a placeholder.
What it doesn't do
Honest about the limitations:
- No live database connection — can't see actual row counts, current query plans, or buffer cache usage
- No query history — each analysis is stateless
- LLM availability depends on HuggingFace free tier — cold starts can add latency
- LATERAL join correlation not yet detected
- No stored procedure analysis
Full limitations: LIMITATIONS.md
If you've ever been handed a slow query with no DBA to ask — I'd genuinely value your feedback. Especially from Oracle and SQL Server users where
I have the least real-world testing.
Sudhakar Sajja is an Application Architect at TechMahindra based in Mississauga, Canada. He writes about DevOps, cloud architecture, and AI-powered developer tooling at autoshiftops.com.
Top comments (0)