percentiles

percentiles

Calculates multiple nearest-rank percentiles of a numeric expression in one aggregation. Use with summarize, optionally grouped with by.

Spec

percentiles(expression, percentile [, percentile ...])
(name [, name ...]) = percentiles(expression, percentile [, percentile ...])

Parameters

  • expression — An int64, uint64, or real column or expression.
  • percentile — A constant numeric value from 0 through 100, inclusive. Integer and fractional values, constant expressions, and constant let variables are supported.
  • name — Optional output column names, one per requested percentile.

Return Value

One real column per requested percentile, in argument order. Default names are percentile_<column>_<percentile>; decimal points in percentiles become underscores. A single assignment, such as latency = percentiles(duration, 50, 95), prefixes these names with latency_. Use explicit column names for complex expressions.

Null inputs are ignored. Empty input without by produces one row of nulls; empty input with by produces no rows. Groups containing only null values produce null percentiles.

The implementation collects and sorts values once per group, selecting rank max(1, ceil(percentile * count / 100)). Percentile 0 returns the minimum and percentile 100 returns the maximum. Grouped partial states can spill to disk and merge under the query memory budget. Memory and spill storage grow with the input size; ungrouped aggregation must fit within the query memory budget.

Unlike Microsoft's approximate T-Digest calculation, these results use exact nearest ranks over the real-converted input values. The existing percentile() function retains its linear interpolation behavior for compatibility.

Example

datatable (duration: int64) [ 10, 20, 30, 40 ]
| summarize percentiles(duration, 50, 95, 100)
percentile_duration_50percentile_duration_95percentile_duration_100
204040
datatable (service: string, duration: real) [ 'api', 10.0, 'api', 20.0, 'worker', 30.0 ]
| summarize (p50, p95) = percentiles(duration, 50, 95), requests = count() by service
| order by service asc
servicep50p95requests
api10202
worker30301

To draw a line for each percentile over time:

Requests
| summarize (p50, p90) = percentiles(Duration, 50, 90) by timestamp = bin(Timestamp, 1m)
| order by timestamp asc
| render timechart with (fill = false)

Each percentile column becomes a separate line. Add a string grouping field to by to draw a line for each percentile and group.