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 constantletvariables 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_50 | percentile_duration_95 | percentile_duration_100 |
|---|---|---|
| 20 | 40 | 40 |
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| service | p50 | p95 | requests |
|---|---|---|---|
| api | 10 | 20 | 2 |
| worker | 30 | 30 | 1 |
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.