SQLIndexesintermediate
Updated:

SQL Indexes Interview Questions and Answers

7 min read

The indexing questions asked in almost every SQL and backend interview — clustered vs non-clustered, composite column order, covering indexes, and when an index is ignored — answered properly.

TL;DR – Quick Answer

SQL index interviews focus on how indexes speed reads and cost writes: the B-tree structure, clustered vs non-clustered, composite index column order and the leftmost-prefix rule, covering indexes, selectivity, and the common reasons an index is ignored — functions on the column, leading wildcards and implicit type casts. Interviewers grade you on reading an execution plan and justifying which index you would create.

On This Page

Indexing is the SQL topic that decides whether a query returns in milliseconds or minutes, so it appears in almost every backend, data-engineering and analyst interview above the junior level. Interviewers use it to test whether you understand how data is stored and searched, not just whether you can type CREATE INDEX.

The examples below use orders(id, customer_id, status, created_at, total) and standard SQL. Behaviour is described for B-tree indexes, which are the default in PostgreSQL, MySQL/InnoDB, SQL Server and Oracle.

Why do interviewers ask about indexes?

Because indexing is the clearest test of the read/write trade-off at the heart of database design. Every index makes some reads faster and every write slower, and choosing the right set proves you think about workloads rather than memorizing commands.

An index is a sorted, separately-maintained data structure — almost always a B-tree — that lets the engine find rows without scanning the whole table. The cost is storage plus maintenance on every modification. Answer index questions by naming both sides of that trade every time.

Q1. How does a B-tree index actually speed up a query?

A B-tree keeps keys sorted in a shallow, balanced tree. Instead of scanning N rows (O(N)), a lookup walks from the root to a leaf in O(log N) steps, and range scans read a contiguous run of leaves.

That structure is why a B-tree serves equality (=), ranges (<, >, BETWEEN), sorting (ORDER BY) and prefix LIKE 'abc%' — all of them exploit the sorted order. A hash index, by contrast, serves only equality.

CREATE INDEX idx_orders_created ON orders (created_at);
-- Uses the index: range scan over sorted leaves
SELECT * FROM orders WHERE created_at >= '2026-01-01';

The depth stays tiny even for huge tables — a few levels cover millions of rows — which is the intuition to state: "log-base-high-fanout of N is a very small number."

Interview note: Follow-up: "when is a hash index better than a B-tree?" Only for pure equality lookups with no range or ordering needs — rare enough that B-tree is the default everywhere.

Q2. Clustered vs non-clustered index — explain the difference.

A clustered index stores the table rows in the index's key order, so its leaf level is the data and there can be only one per table. A non-clustered index is a separate structure of key plus a pointer back to the row, and a table can have many.

In SQL Server and MySQL/InnoDB the primary key is the clustered index by default, so the physical row order follows the PK. A non-clustered index lookup finds the key, then follows the pointer to fetch the rest of the row — the extra step called a "bookmark lookup" or "key lookup".

-- InnoDB: PK is clustered; this secondary index is non-clustered
CREATE INDEX idx_orders_customer ON orders (customer_id);

Note the dialect nuance: PostgreSQL heap tables have no clustered index in the SQL Server sense (the CLUSTER command is a one-time physical reorder, not maintained). Mention this and you show you know indexing is engine-specific.

Interview note: Trap: "why can there be only one clustered index?" Because the rows can be physically sorted exactly one way; ordering them by two keys at once is impossible.

Q3. In a composite index on (a, b, c), which queries can use it?

Queries that filter on a leftmost prefix: a; a, b; or a, b, c. A query filtering only on b, only on c, or on b, c cannot use the index efficiently — this is the leftmost-prefix rule.

CREATE INDEX idx_orders_cs ON orders (customer_id, status, created_at);

SELECT * FROM orders WHERE customer_id = 42;                          -- uses index
SELECT * FROM orders WHERE customer_id = 42 AND status = 'PAID';      -- uses index
SELECT * FROM orders WHERE status = 'PAID';                           -- cannot use it well

Column order is therefore a design decision driven by your query patterns: put the column used in every query first, and the column used for ranges last (a range stops the index from filtering later columns). This ordering rule is the most practical index insight you can demonstrate.

Interview note: Follow-up: "where do you place a column used only for ORDER BY?" After the equality-filter columns, matching the sort direction, so the index also satisfies the sort and avoids a separate sort step.

Q4. What is a covering index and why is it fast?

A covering index includes every column the query touches — filters and outputs — so the engine answers entirely from the index and skips the lookup back to the table row.

-- Query needs customer_id (filter) and total, status (output)
CREATE INDEX idx_cover ON orders (customer_id) INCLUDE (total, status);  -- SQL Server / PG

SELECT total, status FROM orders WHERE customer_id = 42;

The INCLUDE clause (PostgreSQL and SQL Server) stores extra columns at the leaf without making them part of the sort key. In MySQL you achieve the same by adding the columns to the composite key. Explaining that the win comes from eliminating the key lookup — not from the search itself — is the senior-level framing.

Interview note: Trap: "is a bigger covering index always better?" No — extra columns bloat the index, slowing writes and cache efficiency. Cover only the hot queries that justify it.

Q5. What is selectivity, and why does it decide whether an index is used?

Selectivity is the fraction of distinct values — high selectivity (many distinct values, like an email) makes an index useful; low selectivity (few values, like a boolean or a status with two options) often makes a full scan cheaper.

If a status column is 90% 'PAID', an index on it barely narrows the search, so the optimizer may scan the table instead — reading a filtered index and then fetching most rows individually is slower than one sequential scan.

-- Low selectivity: optimizer may ignore this on a mostly-PAID table
SELECT * FROM orders WHERE status = 'PAID';

The takeaway to state: index the columns your queries filter on and that are selective. A partial index (WHERE status = 'CANCELLED') can index just the rare, useful subset.

Interview note: Follow-up: "how does the optimizer know selectivity?" From table statistics/histograms. Stale statistics cause bad plans — running ANALYZE/UPDATE STATISTICS is the fix.

Q6. Why would a perfectly good index be ignored?

Because the predicate is not "sargable" — search-argument-able. Wrapping the column in a function, a leading wildcard, or an implicit type cast all prevent index use.

-- NOT sargable: function on the column defeats the index
SELECT * FROM orders WHERE YEAR(created_at) = 2026;

-- Sargable rewrite: index on created_at can be used
SELECT * FROM orders WHERE created_at >= '2026-01-01'
                       AND created_at <  '2027-01-01';

Other classic causes: LIKE '%abc' (leading wildcard can't use the sorted prefix), comparing an indexed VARCHAR column to a number (implicit cast), and OR across different columns. Being able to rewrite a non-sargable predicate into a sargable one is a frequently tested skill.

Interview note: Trap: "how do you confirm the index was skipped?" Read the execution plan (EXPLAIN / EXPLAIN ANALYZE). Never guess — the plan is the source of truth.

Q7. What is the cost of over-indexing?

Every INSERT, UPDATE and DELETE must maintain each affected index, so a table with ten indexes pays ten times the write overhead. Indexes also consume storage and compete for buffer-pool memory.

On a write-heavy table — an events or logging table — a lean set of indexes can outperform a heavily indexed one overall, because inserts stop stalling on index maintenance. The interview answer is the balance: enough indexes to serve real read queries, no more.

-- Find unused indexes before adding more (PostgreSQL)
SELECT indexrelname, idx_scan FROM pg_stat_user_indexes WHERE idx_scan = 0;

Auditing for unused indexes and dropping them is a maintenance habit worth mentioning — it shows you manage the index set over time, not just at creation.

Interview note: Follow-up: "does an index slow down a bulk load?" Yes — a common pattern is to drop non-essential indexes, load, then rebuild them, which is faster than maintaining them row by row.

Q8. How do you decide which index to create for a slow query?

Read the execution plan to find the expensive step, identify the filter and join columns, and create an index whose leading columns match the equality filters, with range/sort columns last — then verify the plan changed.

EXPLAIN ANALYZE
SELECT total FROM orders
WHERE customer_id = 42 AND status = 'PAID'
ORDER BY created_at DESC;
-- Candidate: (customer_id, status, created_at) — equality first, sort column last

Naming the process — measure, design, verify — matters more than the specific index. Interviewers score whether you would confirm the improvement with the plan rather than assuming the index helped.

Interview note: Trap: "you added the index and it's still slow — now what?" Check statistics freshness, whether the predicate is sargable, and whether selectivity is too low for the index to help at all.

How to prepare

Load a table with a few hundred thousand rows and run EXPLAIN ANALYZE before and after creating each index — watching a sequential scan turn into an index scan makes the leftmost-prefix and sargability rules permanent. Deliberately break an index with YEAR(created_at) and then fix it with a range predicate; that single exercise inoculates you against the most common index interview trap.

Pair this with the normalization questions, since keys and normal forms drive which columns you index, and the constraints set, because primary and unique constraints create indexes automatically. For the storage model underneath, the SQL learning path is the foundation. A mock interview that hands you a slow query and a plan is the closest simulation of the real index round.

Frequently Asked Questions

What is the difference between a clustered and a non-clustered index?
A clustered index defines the physical order of the table's rows, so there can be only one, and the leaf level is the table data itself. A non-clustered index is a separate structure holding the key plus a pointer (row locator or clustered key) back to the row. You can have many non-clustered indexes on one table.
Does adding indexes always improve performance?
No. Indexes speed up reads that can use them but slow down INSERT, UPDATE and DELETE because every index must be maintained, and they consume storage. On write-heavy tables, too many indexes hurt overall throughput. The goal is the minimum set of indexes that serves your real query patterns.
What is the leftmost-prefix rule in a composite index?
A composite index on (a, b, c) can be used for queries filtering on a, on a and b, or on a, b and c — always starting from the left. A query filtering only on b or only on c cannot use it efficiently. This is why column order in a composite index is a deliberate design decision.
What is a covering index?
A covering index contains every column a query needs — both the filter columns and the selected columns — so the database answers the query from the index alone without touching the table. This avoids the extra lookup back to the row and is one of the biggest wins for hot read paths.
Why would the optimizer ignore an existing index?
Common reasons: wrapping the indexed column in a function, a leading-wildcard LIKE, an implicit type conversion, low selectivity where a full scan is cheaper, or stale statistics. If a query that should use an index does a full scan, check the plan and the predicate before adding more indexes.

Want to Build Your Career in Java Full Stack with AI?

Join CodeBegun and train with working industry engineers — Check the Java Full Stack training details

Apply for Demo Class →
Siva Prasad Galaba
Founder, CodeBegun · Staff Engineer

Founder of CodeBegun. 15+ years building Java systems at companies like Crunchyroll. Teaches Java, Spring Boot and system design the way the industry actually works, and mentors students through projects, mock interviews and placement preparation.

Technically reviewed by CodeBegun Technical TeamLast reviewed 16 July 2026 LinkedIn
Chat with us