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 里,需要外套一层子查询。