Paste any SQL SELECT and instantly detect common performance anti-patterns. Get actionable suggestions with before / after examples.
Analysis updates as you type
Needs Work
2 warnings · 1 suggestion
table.* selects all columns from a joined table with the same drawbacks as SELECT *.
Specify only the columns you actually need.
WHERE YEAR(created_at) … forces the database to evaluate YEAR() for every row rather than using an index on `created_at`.
Rewrite the predicate to isolate the bare column on one side of the comparison.
Without LIMIT, the database must sort all matching rows before returning any results. On large tables this can be slow and memory-intensive.
Add LIMIT N if you only need the top rows. If all rows are needed, ensure the ORDER BY columns are indexed.
Many SQL performance problems are caused by a small set of recurring patterns. Learning to spot them — and knowing how to fix them — will make your queries significantly faster on real production data.
Selecting all columns prevents the database from doing an index-only scan, which reads data directly from the index without touching the main table. On wide tables, this can multiply I/O by 5–10×. It also pulls unnecessary data across the network and into application memory. Always list the specific columns you need.
Without a WHERE clause, the database reads every row in the table regardless of how many rows match. On a million-row table with no filter, even an indexed query becomes a sequential scan. Always ask: "Do I actually need every row?"
A B-tree index is ordered by the value stored in the column. A leading wildcard (LIKE '%smith') cannot use this ordering because any value could match. The fix is to restructure the search to a suffix match (LIKE 'smith%'), or use a full-text index for arbitrary substring searches.
| Pattern | Index usable? |
|---|---|
LIKE 'smith%' | ✅ Yes |
LIKE '%smith%' | ❌ No |
LIKE '%smith' | ❌ No |
SQL uses three-valued logic: TRUE, FALSE, and UNKNOWN. When you compare any value to NULL, the result is UNKNOWN. NOT IN works by comparing each value against the entire subquery result. If the subquery returns even one NULL, the entire condition evaluates to UNKNOWN for every row — returning zero results.
-- Bug: if order_items has a NULL product_id, returns NOTHING
SELECT * FROM products
WHERE id NOT IN (SELECT product_id FROM order_items);
-- Safe: LEFT JOIN pattern
SELECT p.*
FROM products p
LEFT JOIN order_items oi ON p.id = oi.product_id
WHERE oi.product_id IS NULL;Wrapping a column in a function call prevents the database from using an index on that column. The database must evaluate the function for every row, turning what could be an index seek into a full scan:
-- ❌ Index on created_at is NOT used
WHERE YEAR(created_at) = 2024
-- ✅ Index on created_at IS used
WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'Sorting requires the database to accumulate all matching rows, sort them, then return the result. Without a LIMIT, this cannot be short-circuited — even if the application only ever uses the first page of results. Add LIMIT and use cursor-based pagination for large datasets.
This tool is best at finding obvious static risks quickly. It is not a replacement for execution plans, but it is a strong first pass before you open the database console.
Start here when a dashboard query technically works but still feels expensive on large tables.
Useful for catching the static mistakes that slip into application code before they hit staging.
Useful when optional filters, sorting, or dynamic query assembly make the final SQL harder to reason about.
Static warnings are more useful when they connect to the right concept cluster. These paths turn a flagged pattern into a more specific reading route.
Use this path when the analyzer highlights scan-prone predicates, broad SELECT lists, or ordering patterns that likely need plan-level follow-up.
Relevant when the query shape looks suspicious because grouping, joins, or null semantics may be producing the wrong answer.
This is the right bridge when your review target was generated at runtime and must be checked for both maintainability and safety.
The analyzer tells you what pattern looks suspicious. These guides explain why the database behaves that way and what a stronger query shape looks like.
Best follow-up when the analyzer flags wildcard searches or full scan risk.
Use this after the analyzer to validate what the optimizer actually chose.
Broader context for the recurring mistakes this tool is designed to catch.
Use this when the query is assembled at runtime and you need both safe construction and analyzable SQL output.
Important when query review is also a security review and user-controlled input may influence SQL structure.