What is a database index?
verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated 2026-10-20
- tool
- SQL
- versions
- SQL databases
- os
- any
A database index is an extra data structure, kept sorted by one or more columns, that points to the rows of a table. With an index on email, a query WHERE email = ? jumps to the matching entries instead of scanning every row. Most engines use B-trees by default, which also serve range conditions (<, BETWEEN) and ORDER BY.
Before and after, in the query plan
python - <<'EOF'
import sqlite3
db = sqlite3.connect(":memory:")
db.execute("create table users (id integer primary key, email text, country text)")
db.executemany("insert into users (email, country) values (?, ?)",
[(f"user{i}@example.com", "IT" if i % 2 else "DE") for i in range(10000)])
plan = lambda sql: [row[-1] for row in db.execute("explain query plan " + sql)]
q = "select id from users where email = 'user42@example.com'"
print("without index:", plan(q))
db.execute("create index users_email on users (email)")
print("with index: ", plan(q))
EOFOutput
without index: ['SCAN users'] with index: ['SEARCH users USING COVERING INDEX users_email (email=?)']
SCAN users reads the whole table; SEARCH users USING INDEX users_email (email=?) looks the value up in the index.
Trade-offs
| Aspect | Effect of an index |
|---|---|
| Reads filtering or sorting on the column | much faster |
| INSERT, UPDATE, DELETE | slower: every index must be updated |
| Storage | extra space on disk and in memory |
| Low-selectivity columns (a boolean) | often ignored by the planner |
| Multicolumn index (a, b) | helps filters on a, or on a and b; usually not on b alone |
| Primary keys and UNIQUE constraints | create an index automatically |
Check what the engine actually does with EXPLAIN QUERY PLAN (SQLite), EXPLAIN ANALYZE (PostgreSQL) or EXPLAIN (MySQL) instead of adding indexes by guesswork.
Sources
Related pages
compare · sqlSQL INNER JOIN vs LEFT JOIN: which rows each one returnsINNER JOIN returns only rows that match on both sides; LEFT JOIN keeps every left row and fills NULL where nothing matches. Shown with real query output.config · sqliteSQLite PRAGMA journal_mode=WAL: concurrent readers and a writerPRAGMA journal_mode=WAL makes SQLite write changes to a -wal file, so readers keep working while one connection writes. It is stored in the database file.cheat sheets · postgresqlpsql cheat sheet: connect, list, describe and run SQL filespsql cheat sheet: connection strings, \l \dt \d+ and \du, switching database, expanded output, timing, running files with -f, \copy to CSV, and catalog queries.