Skip to content

Commit d18125b

Browse files
zzylolclaude
andcommitted
docs: Pass 1 HAVING placement and filters keep candidates
The dev doc describes per-consumer HAVING entries, the adjacent-form scope and that TopK Hydra is added in #605. planner-layering says a filter or HAVING does not prevent accumulator or summary candidates, and Example 1 says Sum has no summary family rather than pruned ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
1 parent dcc3f64 commit d18125b

2 files changed

Lines changed: 34 additions & 16 deletions

File tree

‎docs/design_docs/proposals/planner-layering.md‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,9 +319,14 @@ Each target gets one exact option. If its intent has an exact mergeable
319319
accumulator (Count, Sum, Min, Max, Rate, IRate, Increase; avg via exact sum and
320320
count accumulator states) and the accumulator can be built, the exact option is
321321
**exact accumulator state**: a `SummaryAgg` with an exact family →
322-
`FinalizeExactAccumulator`. Otherwise, for example when a filter or HAVING
323-
prevents the accumulator or the intent has none, it is the plain exact
324-
computation. Whether the accumulator is materialized is decided in Stage 2.
322+
`FinalizeExactAccumulator`. Otherwise, when the intent has no exact
323+
accumulator or it cannot be built (for example avg over a nullable input), it
324+
is the plain exact computation. A filter or HAVING does not prevent the
325+
accumulator or summary candidates: a per-measure filter goes into
326+
`SummaryAgg.filter`, a HAVING that reads only group keys is pushed below the
327+
aggregate as a row predicate, and a HAVING that reads aggregate values is a
328+
`Filter` above the output, with `guarantee = None` for approximate
329+
candidates. Whether the accumulator is materialized is decided in Stage 2.
325330

326331
Each candidate records its input expression, filter, grouping, window,
327332
supported estimates and accuracy requirement. Pass 2 uses these to decide
@@ -400,7 +405,7 @@ flowchart LR
400405
subgraph R2["Replacements(s₂)"]
401406
direction TB
402407
d3["Exact Sum accumulator<br/>per job"]:::exact
403-
a2["summary candidates<br/>✗ pruned: cannot be exact"]:::pruned
408+
a2["no summary candidates:<br/>Sum has no summary family"]:::exact
404409
end
405410
subgraph R3["Replacements(s₃)"]
406411
direction TB

‎docs/develop_docs/local-logical-candidates.md‎

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ ASAP optimization in [planner layering](../design_docs/proposals/planner-layerin
88
inventory containing the original named roots and one `LocalLogicalTarget` per
99
eligible aggregate measure. Discovery includes operator producers read by
1010
scalar roots and expressions. Pointer identity prevents repeated discovery of one
11-
shared producer. Inputs with assigned execution timing or ASAP operators are
12-
rejected: the input `LogicalDAG` contains no ASAP summary choices.
11+
shared producer. Inputs with assigned execution timing or materialization, or
12+
with ASAP operators, are rejected: the input `LogicalDAG` contains no ASAP
13+
summary choices or physical annotations. An approximate accuracy requirement
14+
needs epsilon and delta in (0, 1); otherwise enumeration fails with
15+
`InvalidAccuracy`, naming the root and measure.
1316

1417
## Eligibility
1518

@@ -43,16 +46,22 @@ the target keeps every candidate and records how the predicate is applied:
4346

4447
- A measure's own filter is recorded as `LocalLogicalTarget.filter`; only
4548
rows that pass it update the state (`SummaryAgg.filter`).
46-
- `HAVING` is recorded as `LocalLogicalTarget.having`. The SQL frontend lowers
47-
`HAVING` to a `Filter` directly above the aggregate, so that `Filter` counts,
48-
as does the aggregate's own `having`. A predicate that reads only `by(...)`
49-
group keys is `HavingPlacement::BelowAggregate`: it is pushed below the
50-
aggregate as a row predicate, like a measure filter. A predicate that reads
51-
aggregate values is `HavingPlacement::AboveOutput`: it stays a `Filter`
52-
above the finalize/estimate output, and approximate candidates of the
53-
target carry `guarantee = None`, since membership near the threshold may
54-
change. When several such filters read one shared aggregate,
55-
`AboveOutput` wins.
49+
- `HAVING` is recorded as `LocalLogicalTarget.having`, one `HavingEntry`
50+
(consumer `Filter`, predicate, placement) each. Only the adjacent form is
51+
recorded for push-down: the aggregate's own `having` (an entry with no
52+
`Filter`) and a `Filter` directly above the aggregate, which is how the SQL
53+
frontend lowers `HAVING`. A predicate that reads only `by(...)` group keys
54+
is `HavingPlacement::BelowAggregate`: it is pushed below the aggregate as a
55+
row predicate, like a measure filter. A consumer `Filter`'s predicate is
56+
pushed below only when every consumer of the aggregate applies the same
57+
predicate; otherwise another consumer would lose rows. Any other `HAVING`,
58+
and every `HAVING` of a global aggregate (no group keys, so its one output
59+
row exists even with no input rows), is `HavingPlacement::AboveOutput`: it
60+
stays a `Filter` above the finalize/estimate output, and approximate
61+
candidates of the target carry `guarantee = None`, since membership near
62+
the threshold may change. A value predicate anywhere above an approximate
63+
output, adjacent or not, gets `guarantee = None` through guarantee
64+
propagation (#575); multi-level push-down is tracked in #664.
5665

5766
For example, an approximate single-column distinct count offers exact execution,
5867
HLL, Theta, KMV and UnivMon; an approximate `count` offers its exact `Count`
@@ -75,6 +84,10 @@ the target's one exact option.
7584
Distinct-tuple counts do not acquire single-value UnivMon alternatives; that
7685
family is not declared for them, so it is not a pruned candidate.
7786

87+
TopK offers its per-group heap summaries (`CmsWithHeap`,
88+
`CountSketchWithHeap`). The grouping-level Hydra candidate ("over all groups")
89+
is not generated in Pass 1 here; it is added in #605.
90+
7891
## Scope
7992

8093
The API accepts no empirical cost or accuracy model, runtime capabilities, storage

0 commit comments

Comments
 (0)