Home/Learn/SQL/B-Tree Index Internals

B-Tree Index Internals

Intermediate
Indexing & Performance

B-Tree indexes store sorted key values in a balanced tree so the database can binary-search to the target leaf node and follow a pointer to the heap row — avoiding full-table scans.

Overview

PostgreSQL and MySQL default to B-Tree indexes for most column types. The tree has a root, internal branch nodes, and leaf nodes. Leaf nodes hold the indexed key value and a pointer (tuple ID / row ID) back to the actual heap row. An index scan navigates the tree then fetches heap pages; a sequential scan reads all heap pages. The optimizer chooses an index scan when selectivity is high enough that fewer pages are touched than in a sequential scan. Expression indexes on LOWER(email) or YEAR(created_at) let predicates match the function output. Partial indexes include only rows matching a WHERE clause, keeping the index small and fast for filtered lookups.

Creating Standard, Expression, and Partial Indexes

CREATE INDEX is non-blocking by default in MySQL; in PostgreSQL use CREATE INDEX CONCURRENTLY to avoid locking. Expression indexes must exactly match the query expression. Partial indexes are ideal for filtering on a low-cardinality column with one dominant value (e.g. active users).

SQL — standard, expression, and partial index creation
-- Standard single-column index on foreign key (always index FK columns)
CREATE INDEX idx_orders_user_id ON orders (user_id);

-- Composite index (covered in a separate concept)
CREATE INDEX idx_orders_status_created ON orders (status, created_at DESC);

-- Expression index: supports WHERE LOWER(email) = 'foo@bar.com'
CREATE INDEX idx_users_email_lower ON users (LOWER(email));
-- Query that benefits:
SELECT id, name FROM users WHERE LOWER(email) = 'alice@example.com';

-- Partial index: only active users (makes index far smaller)
CREATE INDEX idx_users_active ON users (email) WHERE status = 'active';
-- Benefits only queries that include WHERE status = 'active'
SELECT id, email FROM users WHERE status = 'active' AND email = 'x@y.com';

Index Scan vs Sequential Scan (EXPLAIN)

EXPLAIN (or EXPLAIN ANALYZE in PostgreSQL) shows whether the planner chose an index. Low-selectivity columns (e.g. a boolean or status with 2-3 values) may trigger a sequential scan because reading all heap pages is cheaper than random-access index hops.

SQL — EXPLAIN showing index scan vs seq scan
-- PostgreSQL EXPLAIN example
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, amount FROM orders WHERE user_id = 42;
-- Expected plan (user_id indexed):
-- Index Scan using idx_orders_user_id on orders
--   Index Cond: (user_id = 42)
--   Rows: 12  (estimated)  Actual rows: 11

-- Without the index the plan would show:
-- Seq Scan on orders
--   Filter: (user_id = 42)
--   Rows Removed by Filter: 98999

-- Index bloat: after many DELETE/UPDATE operations, run:
VACUUM ANALYZE orders;       -- PostgreSQL: reclaims dead tuples, updates stats
-- MySQL equivalent: OPTIMIZE TABLE orders;

Key Points to Remember

  • 1B-Tree leaf nodes store key + heap pointer; the tree is traversed top-down then heap pages are fetched — called an index scan.
  • 2The optimizer picks sequential scan over index scan when selectivity is low (reading most pages anyway) or the table is tiny.
  • 3Expression indexes must syntactically match the WHERE clause expression exactly, including case and function call.
  • 4Partial indexes carry fewer entries than full indexes, fit in cache better, and update faster — ideal for large tables with a small active subset.
  • 5Index bloat grows after heavy DML; VACUUM ANALYZE (PostgreSQL) or OPTIMIZE TABLE (MySQL) reclaims space and refreshes statistics.
  • 6Always index foreign key columns — unindexed FK columns cause sequential scans on every JOIN and ON DELETE CASCADE.

Interview Questions

Sign in to ask Aria
1

How does a B-Tree index speed up a range query like WHERE salary BETWEEN 50000 AND 80000?

MediumMicrosoft
2

What is a partial index and when would you create one?

MediumAtlassian
3

Why might the query optimizer choose a sequential scan even when an index exists?

HardGoogle
4

What is an expression index and how does it differ from a standard column index?

MediumAmazon

Ask Aria about B-Tree Index Internals

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…