Files
ottyl/tickets/078-metric-comparison-filter-scans-all-buckets-for-every-query.md
T

2.6 KiB

078 — Metric-comparison filters scan every metric's buckets on every query

Summary

Same underlying issue as ticket 077 (iterators should narrow the key range as far as possible, and take a range as a parameter), applied to metrics: a metric-comparison filter (e.g. latency_ms[value]<200 in the filter bar) rebuilds its matching-sequence set from scratch on every single query by scanning all buckets for all metrics, then discarding everything that doesn't match the requested metric name — instead of seeking directly to that metric's key range.

Where

  • EngineSnapshot::bucket_values (src/engine/snapshot/metrics.rs:295-312) ranges IndexKey::MetricBucketSplit..IndexKey::End — every bucket for every declared metric — and filters by name == metric_name inside the filter_map closure. IndexKey::Bucket { metric_name, labels } (src/engine/index_key.rs:23-26) derives Ord on metric_name first, so this is seekable: a lower bound of IndexKey::Bucket { metric_name: metric_name.into(), labels: BTreeMap::new() } and an upper bound one metric name past it would narrow the range to just that metric's buckets.
  • The compare-filter compiler, compile_metric_comparison (src/engine/snapshot/filter.rs:83-104), calls self.bucket_values(metric, None) and builds a fresh HashSet<u64> of matching sequences on every call — this runs once per filter compile, and filters are compiled fresh per query (compile_filter_query, called from src/engine/snapshot/query.rs:46), so a dashboard or search bar polling with a metric-comparison filter re-scans all bucket values every poll interval. Unlike the log sort-helper indexes (src/engine/snapshot/sort.rs), there is no incremental cache here keyed by (metric, param, op, value).

Scope

  • Narrow bucket_values to accept/derive a key range for the requested metric_name instead of ranging MetricBucketSplit..End and filtering by name in the closure. This alone removes the "every other metric's buckets" part of the scan regardless of caching.
  • Separately (bigger win, more invasive — may warrant its own follow-up ticket): consider whether metric-comparison results can be incrementally maintained similarly to sort_helper_indexes (src/engine/snapshot/sort.rs) rather than recomputed per query, if profiling shows compare-filtered dashboard polling is a hot path. Keep this ticket scoped to the range-narrowing fix; note the caching idea here so it isn't lost, but split it out if it turns out to need design work (cache invalidation on new bucket values, per unique filter expression).

Depends on

None. Same principle as ticket 077.