Indexes
PizzaSQL has secondary indexes, but they are much simpler than in a typical database. The most important fact first: index definitions persist, but index entries live only in memory and are rebuilt on demand. Selection is also limited to a single case: a single-column equality predicate.
Creating and dropping indexes
Section titled âCreating and dropping indexesâCREATE INDEX idx_users_email ON users(email);CREATE UNIQUE INDEX idx_users_email ON users(email);CREATE INDEX IF NOT EXISTS idx ON t(col);DROP INDEX idx_users_email;DROP INDEX IF EXISTS idx_users_email;CREATE INDEXverifies the table and every column exist before creating the index.- The index definition (name, table, columns,
uniqueflag,DESCflags) is written to the key-value store, so it survives restarts and is visible to other connections. CREATE INDEXalso builds in-memory entries for the rows that already exist at creation time. If that build fails, the index definition is rolled back.DROP TABLEdrops the tableâs indexes automatically.- Multi-column indexes (
(a, b)) andDESCordering are accepted and stored, but they do not affect how the index is used (see below).
What persists vs. what is rebuilt
Section titled âWhat persists vs. what is rebuiltâ| Aspect | Persisted? |
|---|---|
| Index definition (name, table, columns, unique) | yes, in the KV store |
| Index entries (value â rowids) | no â held in memory only |
In practice this means:
- After an engine restart, an index has no entries until a query triggers a lookup through it. At that point the engine scans the table and reconstructs the valueârowids mapping in memory (
ensureIndex). - Writes (
INSERT/UPDATE/DELETE) keep an already-built in-memory index up to date incrementally, so a warm index stays correct without a rebuild. - Because entries are derived from row data, a rebuild is always consistent with the table; the definition is the only durable state.
When an index is used
Section titled âWhen an index is usedâIndex lookup is attempted for a single-table SELECT whose WHERE clause is, exactly, column = literal (or literal = column). If the engine finds an index whose sole column matches (case-insensitively), it resolves the value to a set of rowids and returns those rows directly.
That is the entire optimization:
- â
WHERE email = 'a@b.c'withCREATE INDEX idx ON users(email)â uses the index. - â
WHERE email = ?orWHERE email = $1â both managed transports bind parameters by rewriting them as literals before execution, so the resulting equality can use the index. - â
WHERE email = lower(x)or any non-literal right-hand side. - â
WHERE age > 30,WHERE age BETWEEN ...,WHERE a = 1 AND b = 2â range and composite conditions are not index-eligible. - â Multi-column indexes are never used by the selection logic, even for a leading-column equality.
- â
ORDER BYnever uses an index for sorting. - â
UPDATE/DELETE/JOINpredicates do not use the index for row selection.
If no index applies, the engine performs a full table scan (it reads every row and applies the filter). There is no cost-based planner deciding between scan and index â the decision is a single heuristic check.
UNIQUE indexes
Section titled âUNIQUE indexesâCREATE UNIQUE INDEX stores the unique flag in the definition (it appears in pg_indexes introspection), but uniqueness is not enforced. Duplicate values are allowed. See Constraints.
Interaction with the row cache
Section titled âInteraction with the row cacheâTable rows and index entries are cached in the running database manager and shared by executors for that database. Writes invalidate or update the relevant cache. An index lookup avoids re-reading the table once it is warm, but the first lookup after an engine restart still materializes the whole table to build the index.
Best practices
Section titled âBest practicesâ- Create single-column indexes on columns used in equality predicates against literals â that is the only predicate shape that benefits.
- Do not bother with composite indexes for query acceleration; they are never used.
- Remember that entries are in-memory state. The first indexed query after an engine restart pays a full scan to build the index.
- Because there is no planner, adding an index never hurts correctness â but it only helps the one recognized predicate shape.