怎么算中位数与百分位
中位数与百分位用分位函数计算:PostgreSQL 提供 percentile_cont(按插值返回连续分位值)与 percentile_disc(返回数据中实际存在的值),写法是 WITHIN GROUP (ORDER BY 列)。MySQL 8 没有等价的内置分位聚合,只能用窗口函数近似或放到应用层算。
基本信息
| percentile_cont | 按插值返回连续分位值 |
|---|---|
| percentile_disc | 返回实际存在于数据中的值 |
| PostgreSQL 语法 | percentile_cont(比例) WITHIN GROUP (ORDER BY 列) |
| MySQL | 无内置分位聚合,用窗口函数或应用层计算 |
| 选择建议 | 长尾延迟与响应时间分布用分位数描述更合适 |
典型使用场景
- 统计响应时间的中位数与 95 分位
- 报表里算金额分布
- 监控告警用分位数而不是平均值
- 对比不同分位判断长尾程度
- 替代「平均值掩盖长尾」的旧口径
PostgreSQL 写法
PostgreSQL 写法
SELECT percentile_cont(0.5) WITHIN GROUP (ORDER BY amount) AS median,
percentile_cont(0.95) WITHIN GROUP (ORDER BY amount) AS p95,
percentile_disc(0.5) WITHIN GROUP (ORDER BY amount) AS median_disc
FROM orders;
-- 分组计算:每个城市的耗时分布
SELECT city,
percentile_cont(0.9) WITHIN GROUP (ORDER BY duration) AS p90
FROM requests
GROUP BY city;MySQL 近似写法
MySQL 近似写法
-- MySQL 8 近似中位数:用窗口函数定位中间行
SELECT AVG(amount) AS approx_median
FROM (
SELECT amount,
ROW_NUMBER() OVER (ORDER BY amount) AS rn,
COUNT(*) OVER () AS n
FROM orders
) t
WHERE t.rn IN (FLOOR((t.n + 1) / 2), CEIL((t.n + 1) / 2));分位函数对照
| 写法 | 返回什么 | 适用场景 |
|---|---|---|
| percentile_cont | 插值得到的连续分位值 | 数值分布统计,可能与实际值不同 |
| percentile_disc | 数据中真实存在的值 | 需要落到具体样本 |
| 中位数 | 0.5 分位 | 比平均值稳健,不受极端值影响 |
| p95 / p99 | 高分位 | 监控长尾延迟 |
| MySQL 近似 | 窗口函数或应用层 | 只能近似,注意排序开销 |
中位数与平均数口径不同:少数极端值会显著拉高平均数,长尾场景(响应时间、金额分布)用分位数描述更贴近真实体验。
MySQL 的近似写法要排序整列:大表上会消耗排序内存与临时空间,先评估再决定是否放到应用层或预计算。
分位数对样本量敏感:数据量小时 p95 可能就等于最大值,展示时要标明样本量与统计窗口,避免读者高估结论。
跨分位对比能看出长尾形态:中位数与 p99 差距很大说明长尾明显,只看中位数正常并不代表整体体验健康。