Skip to content

Commit 892ebe1

Browse files
MagicalTuxclaude
andcommitted
docs: re-scope B9i (covering-scan row order) into B9h after investigation
Investigation found no standalone execution-order bug: graphite already reads a covering index in index-walk order, and whenever graphite and SQLite pick the same covering index the rows match. Every remaining no-ORDER-BY covering divergence is a different access-path choice driven by SQLite's cost model (narrow index vs wide-row table scan; smallest of several covering indexes) — the same B9h/B4 territory the pinned no-stat4 oracle makes un-differential- testable. Folded the covering-scan row-order parity into B9h; no code change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent dd700fc commit 892ebe1

1 file changed

Lines changed: 19 additions & 8 deletions

File tree

ROADMAP.md

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,14 +1240,25 @@ tie/representative order), so they are perf/EQP-fidelity work, not correctness:
12401240
`(b,c)` over `(b)` when a trailing range (`b=? AND c>?`) or a `GROUP BY`/`ORDER BY c`
12411241
can ride the same walk; a *covering* index over a narrower one; the smallest
12421242
covering index for `count(*)`; a covering index for an `IN` list. graphite picks by
1243-
longest-equality-prefix only. This changes the chosen access path, so it risks
1244-
regressing the EQP corpus and must be rolled out shape-by-shape with the full
1245-
differential suite — the single-table analogue of B1b.
1246-
- **B9i — covering-scan / no-`ORDER BY` walk in index order.** A `SELECT DISTINCT b` /
1247-
covering scan with no `ORDER BY` emits rows in rowid order where SQLite walks the
1248-
index; the observable effect is the *representative* row a `DISTINCT`/`GROUP BY`
1249-
keeps under a non-BINARY collation. SQL leaves the order unspecified, so this is
1250-
low-priority parity polish, but it needs the covering read to walk the index b-tree.
1243+
longest-equality-prefix only. It also decides *whether* a no-WHERE query uses a
1244+
covering scan at all (SQLite: narrow index beats a wide-row table scan, plain scan
1245+
beats it on a 2-column table) — so the covering-scan row-order parity (formerly B9i)
1246+
rides here too. This changes the chosen access path, so it risks regressing the EQP
1247+
corpus and must be rolled out shape-by-shape with the full differential suite — the
1248+
single-table analogue of B1b.
1249+
- **B9i — covering-scan no-`ORDER BY` row order → subsumed by B9h (investigated
1250+
2026-07-04, nothing to fix in isolation).** The original premise was wrong: graphite's
1251+
covering read is *already* in index-walk order, and whenever graphite and SQLite pick
1252+
the **same** covering index the rows already match (verified: `SELECT DISTINCT b`,
1253+
`GROUP BY b`, `DISTINCT b COLLATE NOCASE`, `DISTINCT b,c`). Every remaining
1254+
no-`ORDER BY` divergence is a *different access-path choice* — SQLite uses a covering
1255+
index (and its walk order) exactly where its cost model says the narrow index beats a
1256+
full-row table scan (`SELECT b`/`count(*)`/`DISTINCT rowid` over a wide table → covering;
1257+
over a narrow 2-column table → plain `SCAN t`), and picks the smallest of several
1258+
covering indexes. graphite either over-selects a single covering index or stands down
1259+
with two, so the plan **and** the emitted order differ. Reproducing it is pure cost
1260+
modelling (row width, index width, number of indexes) — the same B9h/B4 problem, so
1261+
the row-order parity rides on B9h, not a separate execution-order change.
12511262
- **B9j — collation-aware index *selection* for a non-default-collation index.**
12521263
`collect_eq_constraints`/`collect_range_constraints` now compare an explicit
12531264
`COLLATE` to the *column's* collation (fixes the common bug); a `CREATE INDEX …

0 commit comments

Comments
 (0)