Writing SQL that merely works is easy. Writing SQL that stays fast as your tables grow to millions of rows, and stays readable as other developers (including future you) have to maintain it, takes a bit more discipline. None of the habits below are complicated — they're just easy to skip under deadline pressure, which is exactly when they matter most.
Avoid SELECT *
Pulling every column with SELECT * is convenient while exploring data, but in application code it's a habit worth breaking. It fetches columns you don't need (wasting bandwidth and memory), and it silently breaks if someone adds or reorders columns later. Name the columns you actually need:
-- Avoid
SELECT * FROM employees WHERE department = 'Engineering';
-- Prefer
SELECT id, name, salary FROM employees WHERE department = 'Engineering';
Index the Columns You Actually Filter and Join On
If a column regularly appears in a WHERE clause or a JOIN condition on a large table, it's a strong candidate for an index. Skipping this is one of the most common reasons a query that was fast with test data turns painfully slow once a table has real production volume.
Use EXPLAIN to Understand What's Actually Happening
Most databases support an EXPLAIN (or EXPLAIN ANALYZE) command that shows the query plan — whether it's using an index or scanning the whole table, in what order it's joining tables, and roughly how expensive each step is:
EXPLAIN SELECT id, name FROM employees WHERE department = 'Engineering';
Don't guess why a query is slow — run EXPLAIN and see exactly what the database is doing.
Avoid Wrapping Indexed Columns in Functions
An index on hire_date can't be used if your query wraps that column in a function, because the database would have to compute the function's result for every single row before it could compare — defeating the whole point of the index:
-- Can't use an index on hire_date efficiently
SELECT * FROM employees WHERE YEAR(hire_date) = 2024;
-- Index-friendly: compare against a literal range instead
SELECT * FROM employees
WHERE hire_date >= '2024-01-01' AND hire_date < '2025-01-01';
Use Consistent Naming Conventions
Pick a convention — lowercase snake_case table and column names is the most common across the SQL world — and stick to it everywhere. Singular or plural table names, consistent `id` vs `table_id` foreign key naming, consistent casing: none of these choices matters much in isolation, but inconsistency compounds into real confusion once a schema has fifty tables.
A Few More Habits Worth Building
Always double- and triple-check a WHERE clause exists before running UPDATE or DELETE against production data. Prefer explicit JOIN syntax over old-style comma joins in the FROM clause, since it keeps the join condition visible right next to the tables it connects. And reach for a view or a CTE when a query becomes deeply nested — breaking a complex query into named, readable pieces almost always beats a single giant statement nobody wants to touch six months later.
