VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
How Row Lookups Work (and Why They’re Expensive)
A regular index lookup is two steps:- MySQL searches the index to find which rows match
- For each matching row, MySQL fetches the full row from the table (a “row lookup” or “back-to-table lookup”)
Identifying a Covering Index in EXPLAIN
EXPLAIN tells you when a covering index is in use: look for Extra: Using index. If you’re not yet familiar with EXPLAIN output, Reading EXPLAIN in MySQL covers all the key columns.
Using index — MySQL read only the index. No row lookups.
Now add a column that’s not in the index:
Extra is now empty — MySQL uses the index to find rows, then fetches the full row to get order_total. The row lookup is back.
Designing a Covering Index
The goal is to include every column the query touches — in theWHERE, ORDER BY, GROUP BY, and SELECT list. Column order still follows the leftmost prefix rule for WHERE and ORDER BY filtering:
user_idfirst — the equality filtercreated_atsecond — the sort column (index already ordered, no filesort)statuslast — only in theSELECT, not in filtering or sorting
SELECT columns come last because they don’t affect which rows are found or in what order — they’re just along for the ride.
When Covering Indexes Are Worth It
Frequently Asked Questions
Does a covering index help with SELECT *?
No. An index can only cover a query if it contains every column in the SELECT list. SELECT * selects all columns, so you’d need to index all columns — at that point you’ve essentially duplicated the table as an index, which isn’t useful.
Can a covering index still speed up SELECT * queries?
Yes, partially. Even if MySQL has to do row lookups, the index narrows down which rows to fetch. The improvement comes from the WHERE filtering, not from eliminating row lookups.
How do I know if a covering index would help?
RunEXPLAIN and check Extra. If you see Using index condition or nothing (no Using index), and rows is large, a covering index might help. EXPLAIN ANALYZE shows actual vs. estimated row counts, which is useful for confirming the optimizer’s choices.
Troubleshooting
See also
- How MySQL Indexes Work — B-tree fundamentals that covering indexes build on
- Reading EXPLAIN in MySQL — how to confirm
Using indexin EXPLAIN output - How InnoDB Stores Data — why row lookups are expensive and why covering avoids them

