‘SELECT *’ is (Still) Killing Your DB: Write Safer SQL Queries with Code Samples

‘SELECT *’ is (Still) Killing Your DB: Write Safer SQL Queries with Code Samples

‘SELECT *’ is (Still) Killing Your DB: Write Safer SQL Queries with Code Samples

 

Stop using SELECT * in your queries—you’re silently sabotaging your database performance. Whether you’re optimizing a critical backend service, building an analytics dashboard, or troubleshooting a spike in query latency, using explicit column selections will give you control, clarity, and speed. In this post, we’ll explore the hidden costs of wildcard queries, when they work against you, and how to replace them with safer patterns using real, working SQL examples.

1. Why SELECT * Is Bad Practice

At first glance, SELECT * seems convenient. It fetches all columns from a given table without typing them out individually. However, it comes with serious downsides:

  • Performance hits: You’re transferring unnecessary data over the wire.
  • Coupling to schema: A schema change (e.g., new columns) affects all SELECT * consumers.
  • Harder to debug: Columns aren’t visible in the query, making code opaque.

Example of what NOT to do:

-- Avoid this:
SELECT * FROM users WHERE status = 'active';

If the users table has 20+ columns, this pulls in much more data than likely needed—hurting I/O and memory, especially for large datasets.

2. Specify Only the Columns You Need

The most straightforward fix is to explicitly name only the columns you require. This improves query readability and reduces the result set size:

-- Do this instead:
SELECT id, first_name, last_name, email FROM users WHERE status = 'active';

This version is not only more performant but also communicates intent clearly: you only care about these four fields during processing. Explicit queries are also easier to cache and help the query planner optimize execution better in some databases.

3. Hidden Gotchas: ORM Usage and SELECT *

Even when writing good SQL manually, your ORM (like SQLAlchemy, Django ORM, or Sequelize) may generate SELECT * under the hood. Be careful when using .all() or similar shortcuts.

Example using SQLAlchemy in Python:

# Inefficient query:
session.query(User).filter(User.status == 'active').all()

This converts to SELECT * FROM users WHERE status='active'.

Refactor using individual column selections:

# Safer ORM usage:
session.query(User.id, User.first_name, User.last_name).filter(User.status == 'active').all()

This not only makes your app faster but minimizes memory usage on large paginated results.

4. Impact on Index Usage and JOINs

When you use SELECT * in queries with joins, it can create massive result sets and put strain on memory and disk. Worse, indexes are sometimes bypassed because of unexpected column loads.

-- Not recommended:
SELECT * FROM orders JOIN users ON orders.user_id = users.id WHERE users.country = 'US';

If both tables have dozens of fields, and you don’t need them all, your JOINs end up duplicating irrelevant data.

-- Prefer this form:
SELECT o.id, o.total, u.id as user_id, u.first_name 
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE u.country = 'US';

This also helps reduce transfer time if you’re working with remote DBs or APIs driven through SQL (e.g., GraphQL over SQL backends).

5. Better Schema Agility and Deployment Safety

Here’s an underrated point: using SELECT * couples your code tightly to the schema. Add or reorder a column in your table, and now all your queries might break—or behave unpredictably.

For instance, consider a script that does position-based parsing on result sets. If a DevOps deploy adds an audit column, familiar bugs appear in downstream apps as columns shift unexpectedly.

Explicit columns = predictable programs.

-- Safer during schema evolution:
SELECT id, created_at, updated_at FROM subscriptions;

Conclusion: Audit and Fix Your Queries Today

Let’s recap why SELECT * should be avoided and what to do instead:

  • Specify only the needed columns—manually or via your ORM’s APIs.
  • Leverage tools to audit queries (like SQL logs or APM solutions).
  • Review slow-queries list in your DB and refactor common offenders.
  • Make your SELECT statements future-proof for schema and scaling.

Sometimes convenience isn’t worth the cost—especially when your database is on fire 🔥.

The fix is simple: stop using SELECT * and start being explicit. Your database (and your ops team) will thank you.

 

Useful links: