Skip to content

Add projection pushdown to binary expression#691

Open
yeya24 wants to merge 3 commits intothanos-io:mainfrom
yeya24:projection-pushdown-aggr
Open

Add projection pushdown to binary expression#691
yeya24 wants to merge 3 commits intothanos-io:mainfrom
yeya24:projection-pushdown-aggr

Conversation

@yeya24
Copy link
Contributor

@yeya24 yeya24 commented Feb 19, 2026

Fixes #689

The idea is to reuse the same projection logical optimizer to pushdown projections to binary expression. Binary expression vector operator can use the projection information to skip non projected labels when materializing labels in the join table.

Added comprehensive tests and correctness tests to ensure the correctness.

My local benchmark showed that this helps mainly when label string interning is disabled. We are still using slicelabels in Cortex so it helps with our usecase. Users can choose whether to enable or disable this functionality.

Here is the AI generated benchmark report based on the benchmarks I ran locally.

Binary Projection Pushdown - Benchmark Results

Test Configuration

  • Platform: Darwin arm64
  • CPU: Apple M1 Pro
  • Benchmark: Binary operator initialization + Series() call
  • Build tag: -tags slicelabels (label interning disabled)

Results

Small Dataset (1K series, 10 labels)

Without Projection:

989,740 ns/op, 1,089,628 B/op, 2,178 allocs/op
1000 series with 10 labels each

With Projection:

613,850 ns/op, 418,096 B/op, 2,180 allocs/op
1000 series with 2 labels each (8 labels filtered)

Savings:

  • ✅ Memory: -671 KB (-62%)
  • ✅ Time: -376 μs (-38%)

Large Dataset (10K series, 20 labels)

Without Projection:

17,728,662 ns/op, 22,321,292 B/op, 21,234 allocs/op
10000 series with 20 labels each

With Projection:

10,171,683 ns/op, 4,082,405 B/op, 21,237 allocs/op
10000 series with 2 labels each (18 labels filtered)

Savings:

  • ✅ Memory: -18.2 MB (-82%)
  • ✅ Time: -7.6 ms (-43%)

Key Findings

Scaling Behavior

The optimization's benefits scale linearly with dataset size:

Dataset Series Labels Labels Filtered Memory Saved Time Saved
Small 1,000 10 8 (80%) 671 KB (62%) 38%
Large 10,000 20 18 (90%) 18.2 MB (82%) 43%

Why It Works (with slicelabels)

  1. Full string storage: Each label stores the complete string (~100 bytes)
  2. No interning: Duplicate values stored multiple times
  3. Allocation cost: Creating label strings is expensive
  4. Filtering benefit: Skipping labels avoids allocations entirely

Memory Breakdown (Large Dataset)

Without projection (22.3 MB):

  • Label strings: 10,000 series × 20 labels × ~100 bytes = ~20 MB
  • Metadata: ~2.3 MB

With projection (4.1 MB):

  • Label strings: 10,000 series × 2 labels × ~100 bytes = ~2 MB
  • Metadata: ~2.1 MB

Savings: 18.2 MB (82%)


Impact of Label Interning

With Default Build (Label Interning Enabled)

The optimization provides minimal benefit because:

  • Labels are stored as 8-byte pointers, not full strings
  • Filtering overhead cancels out pointer savings
  • Result: +20% CPU overhead, ~0% memory savings

With slicelabels Build (Label Interning Disabled)

The optimization provides massive benefit because:

  • Labels are stored as full strings (~100 bytes each)
  • Filtering avoids expensive string allocations
  • Result: -43% CPU time, -82% memory usage

Real-World Implications

For Prometheus (Default Build with Interning)

Not recommended - The optimization adds CPU overhead without meaningful memory savings.

For Systems Without Label Interning

Highly recommended - Provides:

  • 82% memory reduction for high-cardinality joins
  • 43% performance improvement
  • Scales linearly with series count and label count

When to Enable

Enable this optimization when:

  1. No label interning: Your system stores labels as full strings
  2. High cardinality: Joins produce 10K+ result series
  3. Many labels: Series have 15+ labels
  4. Selective aggregation: Outer operations use <5 labels
  5. Memory constrained: Every MB matters

Conclusion

The optimization is correctly implemented and provides dramatic benefits for systems without label interning:

  • 82% memory reduction (18 MB saved for 10K series)
  • 43% performance improvement (7.6 ms saved)
  • Linear scaling with dataset size

Signed-off-by: yeya24 <benye@amazon.com>
@yeya24 yeya24 force-pushed the projection-pushdown-aggr branch from 96bd215 to 90d332a Compare February 19, 2026 00:34
Signed-off-by: yeya24 <benye@amazon.com>
Signed-off-by: yeya24 <benye@amazon.com>
@yeya24 yeya24 mentioned this pull request Feb 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

High cardinality Joins caused OOM kill due to large result labels

1 participant