首页 / 聚合
PERCENTILE_APPROX 近似分位数
PERCENTILE_APPROX 计算近似分位数,常用于 P50、P99 这类指标。MaxCompute、StarRocks、Doris、Hive 和 Spark 同名可用,但第三个参数的含义和取值范围不同。Hologres 要用 APPROX_PERCENTILE ... WITHIN GROUP 改写,Flink 较新版本只有精确的 PERCENTILE。
各引擎写法
| 引擎 | 支持 | 写法 | 说明 | 依据 |
|---|---|---|---|---|
| MaxCompute | 支持 | PERCENTILE_APPROX(col[, weight], p[, B]) | MaxCompute 2.0 扩展函数。p 取 0~1,也可以传数组一次求多个分位数。B 是精度参数,默认 10000。可选的 weight 参数为每行指定权重。col 为 NULL 的行不参与计算,p 或 B 为 NULL 时报错。 | 官方文档 |
| Hologres | 需改写 | APPROX_PERCENTILE(p) WITHIN GROUP (ORDER BY col) | Hologres V3.1 起提供,用蓄水池抽样计算,最多保留 8,192 个元素。p 是 0~1 之间的常量。 | 官方文档 |
| StarRocks | 支持 | PERCENTILE_APPROX(expr, p[, compression]) | p 可以是单个值或数组。compression 取 2048~10000,不传或超出范围时按 10000 计算,值越大越精确,内存占用也越多。 | 官方文档 |
| Doris | 支持 | PERCENTILE_APPROX(col, p[, compression]) | p 必须是 0~1 的常量。compression 取 2048~10000。只统计非 NULL 值,组内没有有效数据时返回 NULL。 | 官方文档 |
| Hive | 支持 | percentile_approx(col, p[, B]) | 适用于浮点数在内的数值列,p 也可以传数组。B 默认 10000,列的不同值个数小于 B 时结果就是精确分位数。精确的 percentile 只支持整数列。 | 官方文档 |
| Spark SQL | 支持 | percentile_approx(col, percentage[, accuracy]) | Spark 2.1.0 起提供,别名 approx_percentile。accuracy 默认 10000,相对误差为 1.0/accuracy。返回排序后满足条件的最小值,percentage 可以传数组。 | 官方文档 |
| Flink SQL | 需改写 | PERCENTILE(expr, percentage[, frequency]) | PERCENTILE 是精确分位数,按线性插值计算。2.0 起的文档中有这个函数,1.20 的文档中没有,使用前请按所用版本确认。文档提示在普通分组聚合中开销较大,建议用在窗口场景。 | 官方文档 |
迁移注意事项
- 第三个参数含义不同:MaxCompute 和 Hive 的 B、Spark 的 accuracy 都默认 10000;StarRocks 和 Doris 的 compression 只接受 2048~10000。从 Spark 迁移时,如果写了大于 10000 的 accuracy,要调整到这个范围内。
- MaxCompute 有带 weight 的四参数写法,例如 PERCENTILE_APPROX(col, weight, 0.5),其他引擎没有对应参数。迁移时要先确认第二个参数是权重还是分位点。
- 各引擎的算法不同,结果不会完全一致。MaxCompute 文档写明 p 落在两个值中间时取两者均值,Spark 返回满足条件的最小值,Flink 的 PERCENTILE 用线性插值。P50、P99 这类指标迁移后要实测对比。
- Hologres 的 APPROX_PERCENTILE 需要 V3.1 及以上版本,而且只抽样 8,192 个元素。数据量很大时,尾部分位数(例如 P999)的误差可能偏大。
- Flink 的 PERCENTILE 是精确计算,每条记录都可能触发全量排序。文档建议用在窗口聚合中,流式分组聚合中慎用。
示例
计算每个接口的 P99 响应时间
SELECT api, PERCENTILE_APPROX(cost_ms, 0.99) AS p99 FROM api_log GROUP BY api;SELECT api, APPROX_PERCENTILE(0.99) WITHIN GROUP (ORDER BY cost_ms) AS p99 FROM api_log GROUP BY api;SELECT api, PERCENTILE_APPROX(cost_ms, 0.99) AS p99 FROM api_log GROUP BY api;SELECT api, PERCENTILE_APPROX(cost_ms, 0.99) AS p99 FROM api_log GROUP BY api;SELECT api, percentile_approx(cost_ms, 0.99) AS p99 FROM api_log GROUP BY api;SELECT api, percentile_approx(cost_ms, 0.99) AS p99 FROM api_log GROUP BY api;SELECT api, PERCENTILE(cost_ms, 0.99) AS p99 FROM api_log GROUP BY api;