Rollups and query planning

Rollups pre-aggregate recurring questions so reports read summary rows instead of replaying every event. Query plans show when those summaries can answer a request.

Understand a matching rollup

A rollup groups events by a configured dimension set within a time bucket. For a source report filtered to a country, the engine needs the joint source-and-country combination.

Separate source and country totals cannot reconstruct the relationship between them.

Here is the report we want to accelerate:

var result = await analytics.QueryAsync(new AnalyticsQuery
{
    Range = DateRange.LastDays(30),
    GroupBy = { StandardDimensions.Source },
    Filters = { Filter.Equal(StandardDimensions.Country, "US") },
    Metrics = { Metric.Visitors, Metric.PageViews },
});

Add the matching joint definition to the options before opening the engine:

options.Rollups.Definitions.Add(new RollupDefinition(
    StandardDimensions.Source, StandardDimensions.Country));
options.Rollups.Definitions.Add(new RollupDefinition("plan") { Events = ["purchase"] });

Configure definitions before opening the engine. Ordinary definitions added later cover new data; earlier ranges can still use retained raw events.

The first definition covers the union of the report's source grouping and country filter. The second independently prepares purchase reports grouped by plan. A definition's dimension set must match the stored dimensions needed by the query; adding unrelated dimensions is not a substitute for the required set.

Follow a report's plan

The planner considers the dimensions used by grouping, event filters, and conditional metrics, as well as the requested aggregates and historical coverage.

It can read daily summaries for aligned days, hourly or minute summaries for finer portions, and event history where aggregate coverage is unsuitable. A request can combine sources.

Plan signal Meaning
UsedRollups A configured aggregate tier contributed
UsedRawEvents Event-level data contributed
UsedDimensionIndexes An ordered copy narrowed raw reads
UsedRollupIndexes A covering equality index read aggregate rows
Warnings A condition affects coverage or interpretation

Each step names an event, a time range, and a source. Indexed steps also identify the equality dimension.

Inspect the result returned by the report:

Console.WriteLine($"Complete coverage: {result.Plan.IsComplete}");
Console.WriteLine($"Rollup index used: {result.Plan.UsedRollupIndexes}");
Console.WriteLine($"Dimension index used: {result.Plan.UsedDimensionIndexes}");

foreach (var step in result.Plan.Steps)
    Console.WriteLine($"{step.Event}: {step.Source}, " +
        $"{step.From:O} to {step.To:O}, index: {step.IndexDimension ?? "none"}");

foreach (var warning in result.Plan.Warnings)
    Console.WriteLine($"Warning: {warning}");

UsedRawEvents also includes dimension-index reads because those still aggregate individual event payloads. UsedRollupIndexes identifies the aggregate-index path. These flags can both be true when different parts of a report use different sources.

Use suggestions for recurring queries

When automatic execution falls back because a suitable dimension set is missing, the plan can suggest a definition:

// Apply to the options used to open the next engine.
foreach (var group in result.Plan.RollupSuggestions.GroupBy(x => x.Definition.Id))
{
    var index = options.Rollups.Definitions.FindIndex(x => x.Id == group.Key);
    var current = index >= 0 ? options.Rollups.Definitions[index] : null;
    if (current != null && current.Events == null)
        continue; // This dimension set already covers every event.

    var definition = new RollupDefinition(group.First().Definition.Dimensions.ToArray())
    {
        Events = group.Select(x => x.Event)
            .Concat(current?.Events ?? [])
            .Distinct(StringComparer.Ordinal)
            .ToArray(),
    };
    if (index < 0)
        options.Rollups.Definitions.Add(definition);
    else
        options.Rollups.Definitions[index] = definition;
}

Apply a suggestion to the configuration used to open the next engine. It accelerates newly tracked activity; an ordinary added definition does not rebuild expired or existing history.

Several event metrics can suggest the same dimension set. The example merges their event scopes and updates an existing restricted definition instead of adding duplicate definitions.

Suggestions are advisory. They do not resolve every cause of raw execution, such as segments, range boundaries, or missing optional aggregate state.

Enable the aggregates your reports need

Counts and standard numeric aggregates are stored in rollups. Percentiles, first and last values, and distinct dimension counts require additional state:

options.Rollups.ValueAggregates["load_time"] = ValueAggregates.Percentiles;
options.Rollups.ValueAggregates["temperature"] = ValueAggregates.FirstAndLast;
options.Rollups.DistinctDimensions.Add("tenant");

Without the required aggregate state, the engine uses retained raw events where available. A query that needs unavailable history or disabled raw storage can produce a warning or fail, depending on the request.

Explain slow filtered reports

An unfiltered report may read a few summary rows. Adding a filter can require a different joint combination and much more event-level work.

Report Required stored dimension set Selective rollup-index leader
Group by source source Usually unnecessary for this unfiltered report
Filter source, group by country source + country source
Filter country, group by source source + country country
Filter page, group by source page + source page

The two middle reports share an aggregate combination but need different leading keys for selective equality reads. Session and goal metrics can add separate plan steps with their own requirements.

Dimension indexes narrow matching events. Rollup indexes provide an ordered aggregate path for explicitly selected equality filters. Choose the approach from the report's plan rather than its displayed row count.

Coverage also depends on activation dates, retention, and enabled time tiers. Enabling an index cannot recover expired raw history.