sql无标准median函数,mysql等主流引擎不支持;postgresql 14+等通过percentile_cont/percentile_disc实现,但需全表排序、无法用索引,性能差且内存占用高;手写方案如row_number()+count(*)需两次全表扫描。

SQL里根本没有标准MEDIAN函数
绝大多数主流SQL引擎(如MySQL、PostgreSQL 12之前、SQL Server)压根不提供内置MEDIAN函数。你看到的“支持MEDIAN”通常来自特定版本(如PostgreSQL 14+)、扩展(如percentile_cont模拟),或商业数据库(如Oracle、Redshift)。直接写SELECT MEDIAN(x) FROM t在MySQL或旧版PG里会报错:function median() does not exist。
用percentile_cont或PERCENTILE_DISC替代时的性能陷阱
PostgreSQL 14+ 和 SQL Server 支持percentile_cont(0.5),但性能远不如聚合函数。它必须对整个列排序,无法利用索引加速——哪怕你在x字段上有B-tree索引,percentile_cont仍会触发全表扫描+内存排序。
-
percentile_cont返回插值结果(可能非原始值),PERCENTILE_DISC返回实际存在的值,但两者都强制排序 - 数据量超10万行时,耗时可能比
AVG高5–10倍,且内存占用陡增 - 在WHERE过滤后计算中位数?别指望优化器下推——先算完中位数再过滤,或反过来全表扫两次
手写中位数查询的三种写法和真实开销对比
更常见的做法是用窗口函数或子查询模拟。但每种写法性能差异极大:
- 用
ROW_NUMBER()+COUNT(*):需两次全表扫描(一次计数、一次编号),适合中小表( - 用
OFFSET+LIMIT(如ORDER BY x LIMIT 1 OFFSET N):只扫一半数据,但无法处理偶数行的平均逻辑,且OFFSET在大数据集上依然慢 - 用PL/pgSQL或存储过程预排序+取中间值:可控但失去SQL简洁性,且并发时易成瓶颈
实测:100万行整数列,在SSD上,percentile_cont平均耗时850ms;手写OFFSET方案约320ms;而AVG仅12ms——中位数天然就是高成本操作。
真正影响性能的关键不是函数名,而是是否能避免排序
如果你的场景允许近似中位数(比如监控大盘指标),用采样+APPROX_PERCENTILE(Trino、BigQuery、Spark SQL支持)能降到毫秒级。但若必须精确,唯一能省资源的方式是:提前建好有序物化视图,或用应用层维护一个平衡二叉树结构缓存中位数——SQL本身对此无解。
别被“函数名”迷惑,中位数的本质是排序+定位,所有所谓“高效SQL写法”只是把排序延迟或拆分,没绕过这个硬成本。











