Repository navigation
perf(csr): read target columns once when a hop fetches much of a table - #94
Merged
Merged
Conversation
csr_stats() now reports base_version, the relationship dataset version of the last full build, and unindexed_edges, the live edges held outside the base (appended since that build and not since removed). delta_edges counts every append, including ones later deleted, so it can't answer that. Tombstones that remove appended edges are counted separately in Adjacency to make the live count exact.
The fused target lookup fetched the target's columns with take_rows for every chunk. When a hop expands a large share of a Lance node table, each chunk of scattered rows touches most of the column's pages, so the hop pays about one column read per chunk while a hash join reads the table once. Count the target rows an expansion fetches, shared across partitions as the relationship-filter mask does. Once they pass 1/8 of the node table, scan the needed columns (output plus target-filter columns) once with row ids and gather from memory for the rest of the query. Row ids are mapped explicitly, so fragments, deletions and stable row ids stay exact. Small hops and in-memory tables keep their per-chunk gathers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The CSR's fused target lookup fetched the target's columns with
take_rows, one chunk of expanded rows at a time. When a hop reaches a large share of a Lance node table, each chunk of scattered rows touches most of the column's pages, so the hop reads the column about once per chunk, while a hash join reads it once. Since named relationship hops moved onto the CSR, this made IC5 about 69% slower in lazy mode, because itshasMemberhop reads forum titles across about 800k expanded edges.This PR closes #86.
What changed
shortcut:comment marks where a reservation would go.Validation
-D warningsandcargo fmt --check. A new test checks that the scanned columns match fetches by row id, with and without stable row ids, over three fragments with a deleted row, and that an unknown row id fails.count(DISTINCT ...).typospass.Benchmarks. Release wheels, run with the harness in
CONTRIBUTING.md,mainand branch alternating twice. Every run passed against the expected answers. Apple M5, 24 GB, macOS 26.6.2, on AC power. Commits:main0b77246; graph-benchmark-ldbc 5f528da; graph-benchmark-ldbc-complex f3e63fd.main(geomean)mainrunsQueries that changed beyond the gap between
mainruns, lazy mode:mainIC10's +10% comes from one branch run taken at load average 8 (mean 153 ms, fastest round 132 ms). The other three branch runs measured 128.7 to 131.7 ms, the same as
main. Every other query is within 7% ofmain.The memory-mode runs used a build without the one-batch floor. In-memory tables never scan, so the floor can't change them. Without the floor, custom Q17, Q18 and Q27 were 13 to 15% slower in lazy mode; with it, they match
main.Still open after this PR: IC5 in memory mode remains about 20% slower than in 0.4.0 (95.7 ms against 79.8 ms). This change doesn't affect memory mode, so that slowdown ships in 0.5.0 as a known trade-off and is tracked in #92.
🤖 Generated with Claude Code