Catalog B PR 4: grouping and result shaping
This branch integrates main at 86659118 with the expression/filter dependency
from PR #1432 at
349222f7. PR #1432 is still open as this record is prepared. The PR 4 extraction
baseline is 4682fc5f; changes after it add T15 DISTINCT, T16 computed/ordinal
grouping and selectable time buckets, T17 ordering/pagination, and exact
count-distinct composition. The PR must follow #1432 when merging.
Behavior and boundaries
parameterized QL -> reusable plan -> fresh bindings and native scan
-> WHERE -> complete aggregation -> HAVING -> visible expressions
-> DISTINCT -> typed multi-key sorting -> final OFFSET/LIMIT
-> existing measure response
Computed group keys evaluate before aggregation. Exact count-distinct retains complete value sets and never sums overlapping native partial counts. DISTINCT uses the visible tuple, with shared memory accounting and early stopping only where unordered finite pagination permits it. Finite ordered pages retain at most OFFSET + LIMIT owned candidates; unlimited ordering uses budgeted full sort. NULL placement and deterministic tie-break keys are explicit query choices.
Existing native queries, lifecycle-safe empty scalar-count completion and native memory protection retain their merged behavior. Latest main’s native schema coercion, batch merge and array fixes are preserved. This PR adds no protobuf, frame format, persisted storage, toolchain or workflow change. The standalone suite now declares a 4 GiB server allowance, giving these larger combined fixtures a bounded 128 MiB per-query admission limit; the diagnosis is below.
JOINs, CTEs, directory synchronization and full DPO application parity are outside this PR. Parent-child generated cases operate on one measure. Spill and retained page sessions remain deferred. Historical T02 uncertainty and deferred successful 100k/1m owning-query throughput are not changed by this verification.
Verification on the isolated branch
Validation uses source revision d612c057 (subsequent verification-only edits do
not change source). make generate, make lint and make check pass; generated
QL fixtures are current. Race tests pass for pkg/bydbql, pkg/query/ql, all
pkg/query/vectorized/... packages, the focused measure/QL/cache liaison tests,
and the querybench package (567.636 seconds). The broader liaison exception is
recorded below.
Standalone generated QL and native measure compatibility integration passes
935/935 selected cases in 187.974 seconds, inside a four-CPU/8-GiB container
with no extra swap. Report: /mnt/d/qlb-pr4-standalone-final-report.json.
Distributed integration passes 935/935 selected cases in 299.957 seconds
under the same container limits. Report:
/mnt/d/qlb-pr4-distributed-report.json. Both suites select
vec independent verification.*(scanning measures|QL) with -ginkgo.fail-on-empty;
this covers native measure compatibility and generated QL-only execution, not
all stream/trace suites.
The race checks are:
go test -race -tags=querymetrics ./pkg/bydbql ./pkg/query/ql ./pkg/query/vectorized/...
go test -race -tags=querymetrics ./banyand/liaison/grpc -run 'Measure|QL|BydbQL|Compiled' -count=1
go test -race -tags=querymetrics ./test/integration/distributed/querybench
Historical ticket evidence remains in T15, T16, T17, the T15 memory follow-up and the count-distinct follow-up. These historical records do not certify the current PR head.
Scoped benchmark refresh
The final source is measured in isolated four-CPU/8-GiB Docker containers with
no extra swap, GOMAXPROCS=4, Go 1.26.10, and a 256 MiB RPC query tracker.
Timed runs start only after integration and race checks finish. Three repetitions
characterize this extraction; they do not replace historical five-repetition
gates or change T02’s inconclusive verdict.
All 51 kernel controls × 3 repetitions (153 samples) pass, with zero cgroup memory events. Examples of medians:
| Control | Result |
|---|---|
| 100k-row top-k vs full sort, page sizes 10 / 100 | Time ratios 0.0308 / 0.0309; allocated-byte ratios 0.000725 / 0.001878. |
| DISTINCT finite page vs full-input control | 15 vs 1,000 input rows; 18.36 vs 404.31 microseconds; 22.2 vs 146.2 KB allocated. |
| Exact count-distinct, 64 / 65,536 unique keys | 8.48 / 14.66 ms; 6.6 KB / 2.69 MB allocated. Ordinary count is about 2.55 ms / 1.9 KB. |
These are operator controls, including the expected cost of exact distinct state;
the 100k-row kernel is not evidence of successful 100k-row owning RPC throughput.
Kernel artifacts are /mnt/d/qlb-pr4-bench/kernel.txt and kernel-summary.json.
RPC measurements use 1,024/8,192 rows for T15 and 1,024/32,768 rows for T16/T17.
Each small variant uses five warmups and 100 measured calls; each larger variant
uses three warmups and 20 measured calls. T17 composed queries use 96 calls at
one/eight workers. All variants use QL. The three repetitions produce 18 reports,
144 variant measurements, 9,072 timed calls and 288 profiles. All timed calls
succeed; exact-result/hash/cache/cleanup checks pass and all cgroup memory events
are zero. No budget or protocol adjustment was made during timing.
The table reports the median of each repetition’s subject/reference ratio,
then the range across controls. KB and MB here are decimal units.
| Comparison | Rows | p50 latency ratio | p95 latency ratio | Allocated-byte ratio |
|---|---|---|---|---|
| DISTINCT / equivalent GROUP BY, seven controls | 1,024 | 0.977–1.046 | 0.930–1.067 | 0.993–1.016 |
| DISTINCT / equivalent GROUP BY, seven controls | 8,192 | 1.011–1.087 | 0.959–1.071 | 0.987–1.010 |
| Computed explicit/ordinal / stored-key grouping, four controls | 1,024 | 1.009–1.039 | 1.106–1.248 | 1.021–1.036 |
| Computed explicit/ordinal / stored-key grouping, four controls | 32,768 | 0.991–1.028 | 0.966–1.056 | 0.993–1.000 |
| Top-k / full-sort-then-slice | 1,024 | 0.7028 | 0.6548 | 0.6385 |
| Top-k / full-sort-then-slice | 32,768 | 0.3255 | 0.3258 | 0.5549 |
DISTINCT and its GROUP BY control share group-table machinery; this is not an independent-algorithm comparison. The small computed-grouping p95 overhead is observed and retained, without a statistical-significance claim from three runs. Top-k median p50 is 3.481 vs 4.948 ms at 1,024 rows and 42.842 vs 131.605 ms at 32,768 rows. The composed-query concurrency control also passes: one/eight-worker median p50 is 2.762/7.961 ms (1,024 rows) and 37.744/100.992 ms (32,768 rows). These concurrency latencies include contention; they are not speedup ratios.
Raw reports, profiles and reproduction scripts are retained under
/mnt/d/qlb-pr4-bench/. summary.txt, rpc-summary.json, kernel-summary.json
and comparisons-qlb_t15-qlb_t16-qlb_t17.json hold the aggregate measurements.
The non-documentation source manifest (5,007 tracked and nonignored untracked
files) SHA-256 is
41394d48bcd3eef361b289df16b76b0568ced32266b660a6e8f0b0229027c0c4;
source and binary provenance are unchanged across all runs. The scenarios and
controls are documented in the querybench guide.
The untimed T17 overload prerequisite passes with 32 peak in-flight calls:
top-k accepts 94 and rejects 2 for admission; full sort accepts 93 and rejects 3.
All accepted results are exact, cleanup reaches zero, and same-cluster recovery
plus held-capacity rollback/recovery pass. Cgroup memory events remain zero.
Report: /mnt/d/qlb-pr4-bench/overload/t17-overload-1024.json.
Standalone fixture allowance diagnosis
The initial standalone run passed 917/935 selected cases; 18 DISTINCT/sort cases
hit the previously configured 32 MiB per-query admission limit. A single
t15_scalar_zone reproduces without preceding tests. A temporary reservation
probe recorded used=33,536,457 bytes, next charge=25,680, assigned=33,554,432;
the shared 256 MiB pool held only that query’s reservation. The rejection came
from the native scan’s cumulative admission charge, not exhausted process RAM.
With the fixture’s explicit server allowance changed from 1 GiB to 4 GiB, the
per-query limit is 128 MiB. The DISTINCT, bulk top-k and cancellation controls
pass 3/3; successful control reservations reach 66,160,761 bytes (about 63 MiB).
The Docker limit stays four CPUs/8 GiB/no extra swap. Production protection and
small-budget operator rejection tests are unchanged. This configuration change
is not a memory optimization or a revised performance-gate pass. All temporary
protector instrumentation was removed before final validation. Red/probe/control
logs are /mnt/d/pr4-{distinct-red,budget-probe,budget-control}.log.
Pre-existing main test failure
The broader liaison race suite fails TestExportRelay_TwoRelaysShareOneRate.
The isolated test also fails on unchanged main 86659118 (one of three runs):
a relay emits a 98,304-byte piece after its peer finishes, while the test expects
every piece to remain at most 65,536 bytes. The limiter computes piece size from
the currently active relay count. At initial validation, export code/tests were
identical on main and this branch. The CI follow-up corrects the test to allow
the surviving relay’s full-burst pieces while retaining the initial shared-size,
byte/row integrity and combined rate checks; export production code is unchanged.
Base evidence is
/mnt/d/pr4-base-export-control.log. Focused measure/QL/cache liaison race tests
pass. This record does not describe the broader liaison suite as passing.