SQL Query Optimization — SELECT * vs. Specific Columns?
This is a daily Sql challenge from the CodeShot archive. Practice your knowledge of Select Star Vs Specific Columns Performance and improve your technical interview readiness.
-- Option A
SELECT * FROM users WHERE email = 'alice@example.com'
-- Option B
SELECT id, name FROM users WHERE email = 'alice@example.com'
Detailed Explanation
Why This Question Matters
If you've spent any time writing SQL, you've probably seen SELECT * used in a thousand tutorials. It's the fastest way to get a query running during development. But once your table grows from 100 rows to 100 million, that habit starts costing you.
The confusion usually stems from a misunderstanding of how databases actually retrieve data. Many developers think that if the WHERE clause is the same, the performance will be the same. They assume the database finds the row first, and then just "grabs" the columns. In reality, the columns you request change how the database interacts with the disk, the memory, and the network.
Understanding the Code
Let's look at the two options:
On the surface, they do the same thing: they find the user with a specific email. But under the hood, the database engine treats them very differently.
In Option A, you're asking for every single column in the users table. If your table has 50 columns—including large text fields for bios, JSON blobs for settings, or timestamps for every single action—the database has to fetch all of that data from the disk.
In Option B, you're being explicit. You only want the id and the name. This tells the database exactly which pieces of data to pull, allowing it to ignore everything else.
Finding the Correct Answer
The winner is Option B. Here is why.
First, there's the I/O overhead. Data is stored on disk in pages. When you use SELECT *, you force the database to read every column for that row. If you have large columns (like TEXT or BLOB), these are often stored in separate overflow pages. SELECT * forces the engine to jump around the disk to collect all those fragments. By selecting only id and name, you drastically reduce the amount of data being moved from disk to memory.
Second, we have to talk about Covering Indexes. This is where the real performance gains happen.
Imagine you have an index on the email column.
- With Option A, the database uses the index to find the location of the row, then performs a "Bookmark Lookup" (or Key Lookup) to go to the actual table heap and grab all the columns.
- With Option B, if you had a composite index on (email, name, id), the database wouldn't even touch the main table. It would find the answer directly inside the index and return it. This is called a Covering Index, and it's orders of magnitude faster because it eliminates the need to access the raw table data entirely.
Finally, there's the network payload. Sending 10KB of data per row instead of 100KB per row matters when you're scaling to thousands of requests per second.
Common Mistakes Developers Make
The biggest mistake is the "it's fine for now" mentality. Developers often use SELECT * during the MVP stage because it's easier to change the frontend without updating the SQL query. The problem is that this behavior gets baked into the ORM (Object-Relational Mapper) or the API layer.
Another common trap is assuming that the database "optimizes it away." While modern query optimizers are smart, they can't magically ignore the columns you explicitly asked for. If you ask for everything, the engine will give you everything.
Also, watch out for Schema Evolution. If a teammate adds a profile_picture_binary column to the users table, every single SELECT * query in your application suddenly becomes a performance bottleneck. Your app might slow down not because of your code, but because of a schema change you didn't even know happened.
Real-World Usage
In a production environment, we almost never use SELECT *. In high-traffic systems, we follow the principle of Least Privilege Data. You only request the minimum set of columns needed to satisfy the current request.
For example, if you're building a login system, you only need the password_hash and user_id. Fetching the user's address, date_of_birth, and preferences during a login check is a waste of resources.
When I'm auditing a slow production database, one of the first things I look for in the slow query logs is SELECT *. Replacing those with specific columns is often the "low-hanging fruit" that reduces CPU usage and memory pressure without requiring a complex architectural rewrite.
Key Takeaways
- Be Explicit: Only request the columns you actually need.
- Reduce I/O: Fewer columns mean less data read from the disk and less memory used in the buffer pool.
- Leverage Indexes: Specific column selection allows the database to use Covering Indexes, bypassing the main table entirely.
- Avoid Fragility: SELECT * makes your code vulnerable to performance drops when the table schema grows.
- Network Efficiency: Smaller result sets mean faster transmission and lower latency for your API.
Why this matters
Understanding Select Star Vs Specific Columns Performance is crucial for passing technical interviews. In real-world applications, this concept often leads to subtle bugs if not handled correctly. For more details, you can always refer to the official MDN Documentation.