Bounded grouped aggregates and DISTINCT¶
The implementation uses DataFusion 54's grouped hash aggregate and built-in sorted spill/replay, with Flink's local/final stages and exact projected state columns. Signed integer grouping keys and key-only DISTINCT qualify independently of SHA2; standalone global aggregates retain their existing cost gate.
Complete jobs¶
Both engines use the same bounded rowwise Flink datagen source, blackhole sink, parallelism-two local and final stages, 1 GiB managed memory, 128 MiB native off-heap authority, 1,024-row batches and an 8 GiB Java heap. Adaptive automatic parallelism is disabled and the table resource default is two on both engines. Native plans must contain the aggregate, Arrow hash exchange and both perimeter transposes. Every native trial asserts at least the original input row count in aggregate consumption; stock asserts zero. Stock is also the previous StreamFusion whole-query fallback for these grouped queries.
-- Grouped reduction
SELECT k, SUM(v), COUNT(v), MIN(v), MAX(v), AVG(v)
FROM (
SELECT CASE WHEN MOD(id,17)=0 THEN CAST(NULL AS INT)
ELSE CAST(MOD(id*48271,<cardinality>) AS INT) END AS k,
CASE WHEN MOD(id,13)=0 THEN CAST(NULL AS BIGINT) ELSE id END AS v
FROM input
) t GROUP BY k;
-- Key-only DISTINCT uses the same key expression and source.
SELECT DISTINCT k FROM (...) t;
The timer includes executeSql, await and the completed JobExecutionResult.
Source scanning, both row/Arrow conversions, JNI, partial aggregation, blocking
Arrow IPC, final aggregation and sink/job completion remain inside it. Each cohort
uses three warmups and seven retained trials, alternating engine order. These are
complete pipeline comparisons, not isolated kernel ratios or remote-network
throughput measurements. Low/high cardinality describe derived keys; NULL adds an
additional group. The host was shared with independent activity; observed trial
ranges remain in the evidence.
| Workload | Rows | Key cardinality | Stock median ms | Native median ms | Speedup |
|---|---|---|---|---|---|
| Grouped reduction | 1,000,000 | 64 | 180.72 | 119.64 | 1.51× |
| Grouped reduction | 2,000,000 | 65,536 | 350.41 | 182.37 | 1.92× |
| DISTINCT | 1,000,000 | 64 | 141.59 | 109.76 | 1.29× |
| DISTINCT | 2,000,000 | 65,536 | 235.15 | 165.82 | 1.42× |
Measurements are recorded in raw trials. Validation witnesses separately retain unchanged upstream native/fallback contracts, positive admitted SQL work, typed blocking-shuffle replay and the memory controls. The grouped native control consumes 262,144 rows and 65,536 keys under the existing 2 MiB JNI/JVM authority, verifies real spill before EOF, replays every group exactly once and checks all reservations and spill files retire. Native-only pressure controls exercise the same DataFusion path under a 256 KiB pool.
Reproduction¶
Build a release DSO, use SF_BENCHMARK=true, Maven's bench profile and
-Dtest=BatchGroupedAggregateJobBenchmark. Set both native.resource.directory
and java.library.path in sf.extraJvmArgs to that release directory.
sf.batch.grouped.rows, .cardinality, .warmups, .trials, .sha2 and .distinct
control the cohorts. Defaults are 1,000,000, 64, 3, 7, true and false; reported
standalone cohorts set .sha2=false, and DISTINCT cohorts set .distinct=true.
The SHA2 composition adds WHERE SHA2(CAST(id AS STRING),256) <> '' inside the
source subquery and retains all other boundaries. Keep runtime files task-scoped
and remove them after extracting concise evidence.