Scan: Difference between revisions
Wikiservice (talk | contribs) (Refresh MemCP documentation: accuracy, operational guidance, performance profile and maintained API reference) |
Wikiservice (talk | contribs) (Refresh MemCP documentation: accuracy, operational guidance, performance profile and maintained API reference) |
||
| Line 15: | Line 15: | ||
For a query such as: | For a query such as: | ||
< | <pre> | ||
SELECT customer_id, SUM(total) | SELECT customer_id, SUM(total) | ||
FROM orders | FROM orders | ||
| Line 22: | Line 22: | ||
ORDER BY SUM(total) DESC | ORDER BY SUM(total) DESC | ||
LIMIT 20; | LIMIT 20; | ||
</ | </pre> | ||
the logical plan establishes filtering, grouping, ordering, and LIMIT semantics. Physical lowering can then choose a bounded date range, read only <code>created_at</code>, <code>customer_id</code>, and <code>total</code>, fuse filter/aggregation, and apply top-k braking. Use <code>EXPLAIN PHYSICAL</code> to see what was actually selected; SQL spelling alone does not force an index or RecSet. | the logical plan establishes filtering, grouping, ordering, and LIMIT semantics. Physical lowering can then choose a bounded date range, read only <code>created_at</code>, <code>customer_id</code>, and <code>total</code>, fuse filter/aggregation, and apply top-k braking. Use <code>EXPLAIN PHYSICAL</code> to see what was actually selected; SQL spelling alone does not force an index or RecSet. | ||
| Line 46: | Line 46: | ||
These examples illustrate the callback roles; use the exact current signatures from [[Storage]] when writing low-level code. | These examples illustrate the callback roles; use the exact current signatures from [[Storage]] when writing low-level code. | ||
< | <pre> | ||
/* resolve the current transaction and table once */ | /* resolve the current transaction and table once */ | ||
(set tx ((context "session") "__memcp_tx")) | (set tx ((context "session") "__memcp_tx")) | ||
| Line 63: | Line 63: | ||
(scan tx tbl2 '() (lambda () true) | (scan tx tbl2 '() (lambda () true) | ||
'("weight") (lambda (weight) weight) + 0) | '("weight") (lambda (weight) weight) + 0) | ||
</ | </pre> | ||
An ordered scan additionally receives sort expressions/directions, OFFSET and LIMIT. Filtering and local ordering may run in parallel, but output order and order-sensitive reduction remain serial. Do not use side effects as a substitute for a reducer when result order matters. See [[RecSets]] for ordered membership intersection and progressively filtered candidate batches. | An ordered scan additionally receives sort expressions/directions, OFFSET and LIMIT. Filtering and local ordering may run in parallel, but output order and order-sensitive reduction remain serial. Do not use side effects as a substitute for a reducer when result order matters. See [[RecSets]] for ordered membership intersection and progressively filtered candidate batches. | ||
Latest revision as of 12:14, 28 August 2026
Scan
scan, scan_order, scan_order_multi, scan_exists, and transaction-bound variants are physical storage operators emitted after logical planning. Their exact generated signatures are listed under Storage.
The physical lowerer extracts safe equality, range, IN-list, LIKE-prefix, computed-expression, ordering, and RecSet constraints. A boundary may be exact or merely a candidate superset. Candidate boundaries always retain the original SQL predicate as a residual filter.
Column values are read in batches through encoding-specific range or multi-record fast paths. Ordered scans can combine main-index and delta ordering, propagate early stop, and use offset/limit or top-k braking when semantics and cost allow. RecSets identify records for one base relation and visibility snapshot; they do not define join multiplicity or result order. Their adaptive ranges, positive-ID lists, and bitmaps let later scans reuse a narrow domain without materializing wide rows.
Application code should use SQL. Planner contributors must keep scan objects, RecSets, ORC columns, and helper tables out of the parser and logical IR. See Query Planner and Physical Lowering and the repository's INVARIANTS.md.
Reading a plan
For a query such as:
SELECT customer_id, SUM(total) FROM orders WHERE created_at >= '2026-01-01' GROUP BY customer_id ORDER BY SUM(total) DESC LIMIT 20;
the logical plan establishes filtering, grouping, ordering, and LIMIT semantics. Physical lowering can then choose a bounded date range, read only created_at, customer_id, and total, fuse filter/aggregation, and apply top-k braking. Use EXPLAIN PHYSICAL to see what was actually selected; SQL spelling alone does not force an index or RecSet.
Low-level callback contract
Unordered scans can perform shard-local map/reduce work and combine partial accumulators with a second reducer. Ordered scans retain serial output order and own OFFSET/LIMIT/early stop. Update-capable callbacks receive a controlled row-update handle under the scan's transaction and locking rules. The generated Storage chapter is authoritative for parameter names and return types at the referenced commit.
| Stage | Unordered scan |
Ordered scan_order
|
|---|---|---|
| Filter/access path | Parallel per eligible shard; may use indexes/boundaries | Parallel candidate filtering and local ordering where useful |
| Map | Parallel per shard | Applied in requested global order |
| Reduce | Shard-local partial reductions plus a final combine | Serial in output order when order affects semantics |
| Early stop | Cancellation or consumer stop | OFFSET/LIMIT and compatible ordered braking |
Scheme examples
These examples illustrate the callback roles; use the exact current signatures from Storage when writing low-level code.
/* resolve the current transaction and table once */
(set tx ((context "session") "__memcp_tx"))
(set tbl1 (table "schema" "tbl1"))
(set tbl2 (table "schema" "tbl2"))
/* print key/value pairs */
(scan tx tbl1 '() (lambda () true)
'("k" "v") (lambda (k v) (print "tbl1[" k "] = " v)))
/* find a key through an indexable equality predicate */
(scan tx tbl1 '("k") (lambda (k) (equal? k 12))
'("v") (lambda (v) v))
/* shard-local sum with neutral value */
(scan tx tbl2 '() (lambda () true)
'("weight") (lambda (weight) weight) + 0)
An ordered scan additionally receives sort expressions/directions, OFFSET and LIMIT. Filtering and local ordering may run in parallel, but output order and order-sensitive reduction remain serial. Do not use side effects as a substitute for a reducer when result order matters. See RecSets for ordered membership intersection and progressively filtered candidate batches.