Hash (O(1) point) and B-tree (range) indexes, plus expression/partial/adaptive variants. Deep dives:
docs/internals/OPTIMIZER_ARCHITECTURE.md·docs/internals/OPTIMIZER_GUIDE.md
| Index | Lookup shape | Best for |
|---|---|---|
| Hash | =, IN — O(1) point lookups |
exact-match reads, PK/unique lookups |
| B-tree | =, <, <=, >, >=, BETWEEN, ORDER BY |
range scans, sorted access |
| Expression | CREATE INDEX … ON t(lower(name)) |
predicates on expressions |
| Partial | CREATE INDEX … WHERE status = 'active' |
hot subset filters |
| Unique | enforces uniqueness | constraints, idempotent loads |
-- Hash index (default for exact-match workloads)
CREATE INDEX idx_customers_email ON customers (email);
-- B-tree for range queries
CREATE INDEX idx_orders_created ON orders (created);
-- Expression index
CREATE INDEX idx_users_lower_email ON users (lower(email));
-- Partial index
CREATE INDEX idx_open_orders ON orders (status) WHERE status = 'open';⚡ v2.0
HashIndex.Add/Removeoperate on the key only (no full row copy) — index maintenance is allocation-free on the write path.
SimpleSelectPlanbuilds an equality predicate map (column → value).- If an index matches, the optimizer picks the cheapest access path:
- Hash index for exact equality /
INlists - B-tree for ranges and sort pushdown
- Full scan otherwise (SIMD-accelerated — often wins on wide predicates anyway)
- Hash index for exact equality /
- The adaptive index manager may convert between hash and B-tree based on observed query shapes.
- Indexes are kept in sync inside the same transaction as the row write.
- Add/drop indexes with
CREATE INDEX/DROP INDEXSQL;db.VacuumAsync()reclaims space after large index churn. - On bulk
InsertBatch, indexes are updated in keyed batches to avoid re-validation per row.
⚡ Guidance: for pure point-lookup tables (by PK/unique key), a hash index + the
FindByPrimaryKey/ExecuteQueryStructpath is the single fastest read path in the engine. See the Performance Guide.