The raw JSONL workload now runs in 157–278 ms at 1 GiB, compared with 779–975 ms for ClickHouse local on the same machine. This comparison covers complete warm-cache CLI invocations over these generated files. It does not compare persisted MergeTree tables, indexes, joins or a general analytical workload.
Implementation: 4503e0989a3bc29131e7fdca42ba749271d30fe9; final memory-lock
correction: 874153c. Both are local commits. See the
execution checklist.
Apple M4 Pro, 12 logical CPUs, 24 GiB RAM, macOS 26.1 arm64. Rust 1.97.0;
cargo build --release --locked, no custom RUSTFLAGS. ClickHouse local 26.4.4.38,
hyperfine 1.20.0. Main tables show five measured runs after one warmup; controls
use three measured runs after one warmup. All processes include startup, parsing,
execution and CSV formatting; the filesystem cache is warm.
Default logq resolves --threads 0 to 12. ClickHouse uses its defaults in the main
tables. Thread controls are separate; setting thread limits to one does not
restrict every internal/background activity to one CPU.
The 1 GiB file contains 4,680,190 rows; the 100 MiB file contains 457,048 rows. The synthetic JSONL rows have nine flat fields, nine status groups and five user-agent values. Every timed command must exit successfully. An independent bounded-memory oracle verifies all five answers before timing. A separate review also checked the counts, groups, LIKE matches and deterministic TopK ties directly from the generator's periodic construction.
Mean ± sample standard deviation, milliseconds. The baseline used the old implicit single-thread behavior; only its three measured queries are shown.
| Query | Baseline 8baa7fa |
Final logq | ClickHouse local | CH / logq |
|---|---|---|---|---|
| Full-file count | 6,669.0 | 157.1 ± 10.5 | 778.5 ± 6.8 | 4.96× |
| Selective status filter | — | 213.9 ± 14.3 | 962.5 ± 2.2 | 4.50× |
| Group by status | 10,360.5 | 218.0 ± 11.3 | 970.0 ± 10.6 | 4.45× |
| Top-10 latency | — | 277.5 ± 10.0 | 970.0 ± 2.7 | 3.50× |
| User-agent substring | 20,716.6 | 219.2 ± 11.2 | 975.1 ± 11.5 | 4.45× |
Directly comparable baseline-to-final speedups: COUNT 42.5×, GROUP BY 47.5×, LIKE 94.5×. All five final default queries are 3.50–4.96× faster than ClickHouse local in this workload. These are CLI wall-time ratios, not isolated operator speeds or an engine-wide performance guarantee.
| Query | logq, ms | ClickHouse local, ms |
|---|---|---|
| Full-file count | 22.2 ± 1.1 | 244.7 ± 3.0 |
| Selective status filter | 29.1 ± 1.9 | 293.3 ± 2.0 |
| Group by status | 27.0 ± 1.6 | 292.0 ± 2.4 |
| Top-10 latency | 33.3 ± 1.3 | 293.5 ± 7.3 |
| User-agent substring | 28.1 ± 1.8 | 292.8 ± 3.5 |
Startup matters more at this size. Earlier samples, including a 100 MiB LIKE
outlier, remain in phase1-4503e09-*. The final tables use complete new five-run
samples after the memory fix, not selected best runs. Baseline TopK lacked the
new request-id tie-breaker, so its exact before/after speedup is omitted.
1 GiB logq means, milliseconds, measured on core commit 4503e09 without a memory
ceiling. The subsequent fix skips unchanged memory reservations. This sweep keeps
its original provenance; the default tables above were rerun on 874153c.
| Query | 1 thread | 2 threads | 4 threads | 8 threads | ClickHouse settings = 1 |
|---|---|---|---|---|---|
| Full-file count | 1,121.3 | 555.5 | 295.9 | 190.9 | 781.8 |
| Selective status filter | 1,344.5 | 717.6 | 434.6 | 234.4 | 1,515.0 |
| Group by status | 1,385.4 | 721.8 | 430.1 | 240.0 | 1,504.2 |
| Top-10 latency | 1,616.7 | 789.1 | 473.3 | 293.7 | 1,569.9 |
| User-agent substring | 1,408.5 | 700.8 | 378.1 | 221.3 | 1,693.3 |
With one-thread settings, COUNT remains about 43% slower than ClickHouse; TopK is about 3% slower, while the other cases are 8–17% faster. Compared with the original single-thread logq baseline, one-thread COUNT, GROUP BY and LIKE improved about 6×, 7.5× and 14.7×. Default gains combine less work per row with effective parallel execution.
--max-memory caps estimated retained operator state, including queued
batches. It does not cap process RSS, mapped file pages, all transient parser
allocations or OS caches. At 1 GiB, logq RSS was approximately 1,032–1,038 MiB;
at 100 MiB it was approximately 108–113 MiB. Resident mapped input accounts for
the file-size scaling. The original reader used about 8 MiB; --threads 1 still
measured about 8 MiB. Bounded queues remove full-input heap accumulation, not mmap
residency.
All final JSONL queries passed with a 16 MiB operator-state ceiling:
| 1 GiB query | Default mean, ms | 16 MiB ceiling mean, ms |
|---|---|---|
| Full-file count | 157.1 | 161.6 |
| Selective status filter | 213.9 | 217.2 |
| Group by status | 218.0 | 209.1 |
| Top-10 latency | 277.5 | 272.1 |
| User-agent substring | 219.2 | 218.6 |
Controls exposed one more bottleneck: fixed-size group accumulators locked the shared memory counter even when their retained size did not change. Skipping these no-op updates reduced 1 GiB ELB grouping with a ceiling from 485.1 ms to 132.5 ms.
ELB 1 GiB, three-run means, milliseconds:
| Query | Default | 16 MiB ceiling |
|---|---|---|
| COUNT | 39.0 | 39.6 |
| SUM(sent_bytes) | 115.2 | 117.3 |
| GROUP BY status | 131.3 | 132.5 |
| GROUP BY status + WHERE true | 132.7 | 129.0 |
| 5-minute time buckets | 248.0 | 254.7 |
Redundant WHERE true preserves the fast path. The bucket workload includes
timestamp wraparound, so the optimized projection feeds hash grouping without
assuming sorted input. ELB COUNT/groups/buckets are checked exactly. SUM is checked
against an independent total at the existing f32 output precision. Public
Int32/Float32 representation was not migrated in this change.
- Strict direct JSON deserialization, root-field projection and typed batches; preserve ignored-value validation, nested values, NULL/MISSING and duplicate keys.
- Shared mmap, lazy per-file opening, 256 KiB ordered tasks, bounded queues and cancellation; worker-local Count/Sum/Avg states with f64 intermediate sums.
- Correct aggregate aliases/schemas, typed/Mixed keys, scope constants, array dependencies and three-valued predicates.
- Cached LIKE search state and masked dictionary evaluation; reusable tokenizer offsets and group-key buffers.
- Late TopK payload construction, move-based full sorting and stable numeric/null ordering; shared memory reservations that skip unchanged charges.
- Compiled time-bucket projection and memory-accounted grouping. Actual SQL literals and EXPLAIN now select the optimized path.
- Reliable error exits, answer-checked benchmarks, full SQL parsing and correct LIMIT cleanup timing.
Parallel partial aggregation covers Count/Sum/Avg. Heterogeneous MIN/MAX retain sequential semantics. Complex projections, nested sorting, joins and unsupported dynamic shapes conservatively retain row execution. Persisted columnar storage, indexes, external spilling, wider public numeric types and general vectorized expressions remain separate future work. These measurements do not establish performance for high-cardinality groups, wide/nested JSON, gzip, large joins or full sort.
Final cargo test: 954 tests passed. The no-op memory-lock regression failed
before the fix and now passes. All-target/all-feature Clippy with -D warnings,
formatting, 10 Python harness tests and five Criterion smoke targets passed.
Cross-review found and resolved array dependencies, nested ordering, duplicate
aliases, constant projection, lazy shard opening and unordered time buckets.
cargo build --release --locked
CLICKHOUSE_BIN=/path/to/clickhouse-26.4.4.38 \
python3 scripts/bench_e2e/benchmark.py --scale 1gb --tools logq clickhouse \
--runs 5 --warmup 1 --results-dir scripts/bench_e2e/results/reproduction-1gb
# Repeat with --scale 100mb, or --threads 1/2/4/8 for thread controls.Raw artifacts remain in ignored scripts/bench_e2e/results/ directories:
audit-2026-09-05/: baseline and original routing/RSS evidence.phase1-4503e09-100mb/,phase1-4503e09-1gb/: complete pre-memory-fix samples.final-2026-09-05-100mb/,final-2026-09-05-1gb/: final five-run comparisons, verification, query/command snapshots, RSS and metadata.final-2026-09-05-controls/: thread sweep and original budget slowdown.final-2026-09-05-budget-controls/: corrected budget and ELB controls. Both controls directories include their exactrun_controls.pyand raw hyperfine JSON.
Metadata records build_command: null because LOGQ_BIN supplied the prebuilt
binary. The actual build was cargo build --release --locked.
Final binary SHA-256: e1492f8eb16727a9beb5fc9b88ec3aa1c4efc30822d76e80c7cb2e5d323d122b.
1 GiB dataset SHA-256: cc87df3720c3e5b7703874bd2181f34600a928d33bdd73cb223b2531385e4801.