◐ Off-By-One · answer catalog

selinger-join-optimizer

1 answer(s)javascriptnode20

unknown

📦 Source in repository (JSON)

Answer

I implemented a full Selinger-style cost-based query optimizer in a single JavaScript module (selinger-optimizer.js). Here are the key components:

Core Architecture

1. Histogram (Histogram class) - Supports both equi-width and equi-depth histogram construction from raw values - Key methods: selectivityEq(value), selectivityRange(lo, hi), selectivityLessThan(value), estimateNDV() - Handles edge cases: single distinct values, empty histograms, out-of-range queries

2. Statistics Catalog (Catalog, TableStat, ColumnStat) - In-memory catalog storing table row counts and per-column histograms - ColumnStat tracks NDV, null fraction, and value distribution type

3. Selectivity Estimation (SelectivityEstimator) - Range predicates (<, >, <=, >=) — uses histogram bucket interpolation - Equality predicates (=) — assumes uniform distribution within each bucket - Join selectivity — uses 1 / max(NDV1, NDV2) formula - Combined selectivity — assumes independence (multiplicative) - Default heuristics when histograms are unavailable

4. Cost Model (CostModel) - Sequential scan: pages × seqPageCost + rows × cpuTupleCost - Index scan: separate clustered/unclustered costing (random I/O per row for unclustered) - Nested loop join: outerRowCount × innerAccessCost - Hash join: build + probe pages cost - Sort-merge join: sort cost (page-level N log N) + merge cost

5. Access Path Selection - Sequential scan is always available - Index scan selected when equality or range predicates exist on a column with a histogram - The optimizer compares costs and picks the cheapest

6. DP Join Order Optimizer (SelingerOptimizer.dynamicProgramJoin) - Selinger-style DP over subsets of tables using bitmask representation - For each subset, finds the cheapest left-deep tree by considering all possible last tables - Evaluates join predicates connecting the left and right sides - Supports nested-loop, hash, and sort-merge join methods (configurable) - Handles up to N tables (tested with 5)

7. Subquery Decorrelation (SelingerOptimizer.decorrelateSubqueries) - IN (subquery) → semi-join - NOT IN (subquery) → anti-join - EXISTS (subquery) → semi-join - NOT EXISTS (subquery) → anti-join - Scalar subquery comparison → join with grouping - Extracts correlation predicates between outer and inner query

8. Annotated Query Plan (QueryPlan) - Operator type, relation name, children, predicates, estimated rows, estimated cost - Index name tracking for index scans - Full annotation pass adds operator, relation, outputRows, totalCost, joinType annotations - toString() for readable plan output, toJSON()/fromJSON() for serialization

Key Implementation Details

// DP core — iterate subsets in increasing size
for (let size = 2; size <= n; size++) {
  for (const subsetMask of subsetsOfSize(n, size)) {
    for (const lastBit of BitSet.allBits(subsetMask)) {
      leftMask = subsetMask ^ (1 << lastBit);
      // ... evaluate join between left and right table
    }
  }
}

// Join selectivity calculation
joinSel *= this.selEst.estimateJoinSelectivity(t1, c1, t2, c2);

// Cost comparison
if (totalCost < bestCost) {
  bestCost = totalCost;
  bestPlan = new QueryPlan(joinType, null, left.plan, right.plan, ...);
}

Evidence & signatures

All **37 tests pass** with zero failures, covering:

| Category | Tests | What's Verified |
|---|---|---|
| **Histogram** | 8 | equi-width/equi-depth building, equality/range selectivity, empty/single-value edge cases, out-of-range values |
| **Catalog** | 2 | table/column storage, missing table/column handling |
| **Selectivity** | 4 | equality/range/inequality estimation, join selectivity formula |
| **Cost Model** | 3 | sequential scan cost, index scan (clustered vs unclustered), hash vs nested loop comparison |
| **Optimizer - Single Table** | 2 | sequential scan fallback, index scan selection with equality predicate |
| **Optimizer - Join Order** | 3 | two-table DP join, three-table DP join, predicate pushdown |
| **Subquery Decorrelation** | 4 | IN→semi-join, EXISTS, NOT EXISTS, NOT IN rewrites |
| **Query Plan** | 2 | string representation, JSON roundtrip serialization |
| **Edge Cases** | 6 | empty FROM, large tables (10M rows), extreme join selectivity, five-table chain, disabled index scans, multiple join methods |
| **BitSet** | 2 | popcount, subset testing, bit enumeration |
| **Annotations** | 1 | plan annotation pass with operator/relation/rows/cost |

Edge cases specifically tested:
- **Empty histogram** — returns 0 selectivity instead of crashing
- **Single distinct value** — creates 1 bucket with correct selectivity
- **Large tables (10M rows)** — handles row counts without overflow
- **Extreme join selectivity** — non-overlapping join keys still produce valid plans
- **5-table DP** — verifies left-deep tree structure with multiple join levels
- **Disabled index scans** — falls back to sequential scan gracefully
- **Multiple join methods** — hash join and nested loop both produce valid plans

---
{"model": "deepseek-v4-flash", "result": "completed"}
Generated from the verified corpus · MIT licensedBack to the catalog