首页/数据/SQL 速查/NTILE 分桶
聚合与窗口函数54 条

NTILE 分桶

把分区内行按顺序尽量均匀分成 n 桶(1..n),用于分位、TOP 比例抽样等场景。

SQL 速查数据更新于 2026-10-13

NTILE 怎么分桶

NTILE(n) OVER (…) 把分区内的行按给定顺序尽量均匀地分进 n 个桶,编号从 1 到 n;行数不能整除桶数时,靠前的桶多分一行。它按「行数」等频分桶,不是按数值区间等宽分档,这一点决定了它适合分位、分层抽样这类场景。

基本信息

适用平台MySQL 8.0+ / PostgreSQL
语法NTILE(桶数) OVER (PARTITION BY … ORDER BY …)
分桶规则尽量均匀,不整除时靠前的桶多一行
编号从 1 到桶数
桶数超过行数前面的桶各 1 行,其余为空桶

典型使用场景

  • 成绩或消费额分四分位、十分位
  • 按消费额分层抽样做 A/B 实验
  • 性能分档:划出最优一档与末位一档
  • 把大数据集平均切成 n 份并行处理
  • 先按业务维度分区,再在分区内分桶做配额

示例

示例
-- 按成绩分四档
SELECT name, score,
       NTILE(4) OVER (ORDER BY score DESC) AS quartile
FROM exams;

-- 分组内分桶:每个班级各自分层
SELECT class_id, name, score,
       NTILE(10) OVER (PARTITION BY class_id ORDER BY score DESC) AS decile
FROM exams;

-- 只看最优的一档(窗口函数不能写在 WHERE 里,要外套子查询)
SELECT * FROM (
    SELECT name, score, NTILE(4) OVER (ORDER BY score DESC) AS q FROM exams
) t WHERE q = 1;

相邻窗口函数对照

函数编号方式典型输出
ROW_NUMBER唯一序号,不并列1,2,3,4
RANK并列跳号1,2,2,4
DENSE_RANK并列不跳号1,2,2,3
NTILE按行数等频分桶桶号 1..n
需要「按数值区间等宽分档」时 NTILE 不合适:它只看行数不看取值。要固定区间分档,可用数据库的 WIDTH_BUCKET 之类函数,或用 CASE 自己划区间。
分桶依赖 ORDER BY:排序键有并列值时,同一条数据两次执行可能落进不同桶。要结果稳定可复现,在排序里补一个唯一键。
桶号本身不携带业务含义:1 号桶只表示排在最前面那批行,具体分界要结合取值看。给业务方解释时最好同时给出行数区间与取值区间,避免把桶号当成分数区间。
分桶结果可以再参与筛选与聚合,例如只看最优的一档算平均值、按桶统计人数分布;注意窗口函数不能写在 WHERE 里,需要外套一层子查询。

易错点

  • 把 NTILE 当等宽分档:它按行数分桶,重复值可能被分进不同桶,档位边界与数值区间无关
  • 桶数大于行数:前面若干桶各 1 行、其余为空桶,下游按桶号取数时要处理空桶
  • 排序键并列导致分桶不稳定:同一份数据两次执行结果可能不同,需补唯一排序键
  • 在 WHERE 里直接引用 NTILE 的别名:窗口函数晚于 WHERE 求值会报错,需外套一层子查询
  • 以为各桶行数严格相等:不整除时靠前的桶多一行,拿它做等量抽样要接受这个偏差

数据来源与参考

  • MySQL 8.0 Reference Manual · NTILE
  • PostgreSQL Documentation · Window Functions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌