write-sql-query
Use when writing, reviewing, or optimizing SQL queries for correctness, performance, and maintainability
SKILL.mdskills/engineering/data/skills/write-sql-query/SKILL.md
GitHubWrite SQL Query
Write SQL queries that are correct, index-aware, readable, and safe against injection and unintended side effects.
Why This Is Best Practice
Adopted by: PostgreSQL community (Use The Index, Luke), Google (BigQuery SQL style guide), GitLab (SQL query guidelines in engineering handbook) Impact: A missing index on a WHERE clause column can cause full table scans — a 10ms query becomes 10 seconds on a 10M row table. Celko's patterns and index-aware SQL are the standard in performance-critical data engineering.
Why best: Most SQL performance problems have the same root cause: the query does not use an available index, or no appropriate index exists. Writing index-aware SQL from the start costs nothing; retroactively optimizing a slow query in production is expensive and disruptive.
Steps
- Understand the execution plan first — For any non-trivial query:
EXPLAIN ANALYZE(Postgres),EXPLAIN FORMAT=JSON(MySQL), orEXPLAIN PLAN(Oracle) before assuming it is efficient. - Write SARGable predicates — Ensure WHERE clause conditions can use an index: avoid wrapping indexed columns in functions (
WHERE YEAR(created_at) = 2026→ not SARGable;WHERE created_at >= '2026-01-01'→ SARGable). - Select only needed columns — Never
SELECT *in production queries; enumerate columns. Reduces I/O, prevents index-only scan breakage, and avoids surprises when schema changes. - Use JOINs explicitly — Always specify JOIN type (INNER, LEFT, etc.); never use implicit comma-joins in FROM clause. Explicit JOINs are readable and unambiguous.
- Avoid N+1 patterns — Never execute queries inside loops; use JOIN or a subquery to batch the operation. N+1 is the #1 application-layer SQL anti-pattern.
- Use CTEs for readability — Break complex queries into named CTEs (
WITH ... AS (...)) for readability; modern optimizers inline CTEs efficiently (Postgres 12+, BigQuery). - Parameterize all user inputs — Never concatenate user input into SQL strings. Always use prepared statements or parameterized queries; SQL injection is trivially exploitable.
Rules
- Never run an UPDATE or DELETE without a WHERE clause — add a
LIMIT 1guard in development to prevent accidents. - Always test queries on a representative dataset size — a query that runs in 50ms on 1,000 rows may take 50 seconds on 1,000,000.
- Wrap multi-statement data mutations in a transaction; rollback on error.
- Avoid
SELECT DISTINCTas a band-aid — it usually signals a missing JOIN condition or a data model problem.
Examples
Non-SARGable (bad):
SELECT * FROM orders WHERE DATE(created_at) = '2026-03-01';
-- Function on column prevents index use
SARGable (good):
SELECT order_id, total, status
FROM orders
WHERE created_at >= '2026-03-01' AND created_at < '2026-03-02';
-- Range scan on index; only needed columns selected
Common Mistakes
SELECT *in production — fetches unused columns, breaks index-only scans, causes hidden bugs when columns are added/dropped.- Implicit type coercion in WHERE —
WHERE user_id = '42'whenuser_idis integer triggers type cast on every row, preventing index use. - Correlated subqueries in SELECT — executes the subquery once per row; replace with a JOIN or window function.