SQLite Indexes

An index is a separate data structure that SQLite maintains alongside a table to speed up data lookups. Without an index, SQLite reads every row in a table to find matches (a full table scan). With an index, it jumps directly to the relevant rows.

The Phone Book Analogy

WITHOUT INDEX (full table scan):
  To find "Smith, John" in an unordered list of 1 million names,
  you read every entry from top to bottom.
  → Slow: O(n) — must check all rows

WITH INDEX (like a sorted phone book):
  Names are sorted A → Z. You open to "S", then "Sm",
  then jump directly to "Smith, John".
  → Fast: O(log n) — skips most of the data

How SQLite Stores an Index

TABLE: employees (1 million rows)
─────────────────────────────────────────
id │ name    │ email              │ salary

INDEX: idx_email  (on email column)
─────────────────────────────────────────
email (sorted)          │ rowid (pointer)
────────────────────────┼────────────────
alice@company.com       │ 1
bob@gmail.com           │ 2
carol@company.com       │ 3
...

Query: WHERE email = 'carol@company.com'
  1. Binary search index → rowid = 3
  2. Jump directly to row 3 in table
  3. Return result instantly

Creating an Index

-- Basic index on one column
CREATE INDEX idx_email ON employees(email);

-- Safe creation
CREATE INDEX IF NOT EXISTS idx_email ON employees(email);

-- Unique index (also enforces uniqueness)
CREATE UNIQUE INDEX idx_email_unique ON employees(email);

-- Composite index (multiple columns)
CREATE INDEX idx_dept_salary ON employees(dept_id, salary);

-- Partial index (only indexes rows matching a condition)
CREATE INDEX idx_active ON employees(dept_id) WHERE active = 1;

When SQLite Uses an Index

QUERY USES INDEX:                   INDEX BYPASSED:
──────────────────────────────────  ──────────────────────────────────
WHERE email = 'x@y.com'            WHERE UPPER(email) = 'X@Y.COM'
WHERE salary > 50000               WHERE salary + 0 > 50000
WHERE dept_id = 10 AND salary > 5  WHERE salary > 5 AND dept_id = 10
ORDER BY email (with index)        WHERE email LIKE '%@gmail.com'
                                   (leading wildcard defeats index)

Listing Indexes

-- List all indexes
sqlite> .indexes
idx_dept_salary   idx_email

-- Show indexes on a specific table
PRAGMA index_list(employees);

seq │ name            │ unique │ origin
────┼─────────────────┼────────┼───────
0   │ idx_email       │ 0      │ c
1   │ idx_dept_salary │ 0      │ c

-- See columns in an index
PRAGMA index_info(idx_dept_salary);
seqno │ cid │ name
──────┼─────┼────────
0     │ 2   │ dept_id
1     │ 4   │ salary

Dropping an Index

DROP INDEX IF EXISTS idx_email;

Composite Index Column Order Matters

INDEX: idx_dept_salary ON (dept_id, salary)

USES INDEX:
  WHERE dept_id = 10                  ← leftmost column only ✓
  WHERE dept_id = 10 AND salary > 50  ← both columns ✓

BYPASSES INDEX:
  WHERE salary > 50                   ← skips first column ✗

Rule: a composite index supports queries that start from the
leftmost column and move right. Skipping the first column
defeats the index.

Index Trade-offs

BENEFIT                       COST
──────────────────────────    ──────────────────────────────
Faster SELECT / WHERE         Slightly slower INSERT/UPDATE/DELETE
Faster ORDER BY               Extra disk space
Faster JOIN lookup            Index must be maintained on every write

Index every column? No.
Index columns you frequently filter, sort, or join on.

Automatic Indexes

SQLite automatically creates indexes for PRIMARY KEY and UNIQUE columns. You do not need to create these manually.

CREATE TABLE users (
  id    INTEGER PRIMARY KEY,   ← index created automatically
  email TEXT UNIQUE            ← index created automatically
);

Key Takeaways

  • Indexes speed up SELECT queries by avoiding full table scans
  • Create indexes on columns used in WHERE, ORDER BY, or JOIN conditions
  • Composite indexes work best when queries start from the leftmost column
  • Indexes slow down writes slightly — only add them where query speed matters
  • PRIMARY KEY and UNIQUE columns get automatic indexes

Leave a Comment

Your email address will not be published. Required fields are marked *