MPP数据库分片与数据倾斜实战指南:从原理到选型
大家好,我是数据库小学妹👋我踩过的坑,你别再踩。
去年一次架构评审,团队要把单机报表库换成 MPP 数据库。理由很直接,多加几台机器就快了。三个月后,同一个团队凌晨给我打电话。8 个节点,7 个在 20% 上下,1 个跑到 92%。一条汇总 SQL,从 30 秒变成 2 分 06 秒。评审会上的乐观和凌晨的报警,说的是同一件事。机器不是白加的,得先知道查询是怎么跑完的。
这篇把三件事串起来。MPP 数据库在并行什么,数据倾斜怎么找出来,什么场景不该上。看完能少走一段弯路。
MPP 数据库是什么?分片、并行与三类角色
MPP 数据库,底层是 Massively Parallel Processing(大规模并行处理)。落地就三个动作。数据按分布键切到多个节点。查询拆成并行任务。各节点算完,再汇总结果。
它擅长大表扫描、复杂 join、聚合分析。高并发短事务不是它的强项。把它当成单机数据库的加速版,会误判适用边界。它是为分析型负载设计的并行架构。
分布式数据库和 MPP 也不是一回事。前者说的是部署形态,后者说的是计算架构。一个分布式数据库可以是 MPP,也可以不是。MPP 系统通常分布在多节点上。它的强项是分析,不是跨节点事务。
换成角色看更清楚。协调节点负责解析 SQL、生成计划、拆任务、收结果。计算节点只扫自己那份数据,算本地聚合。分片决定每一行落在哪个节点。
| 角色 | 主要做什么 | 出问题时的表现 |
|---|---|---|
| 协调节点 | 解析 SQL、生成计划、拆任务、汇总 | 并发高时先忙不过来 |
| 计算节点 | 扫描本地分片、执行 join 和聚合 | 某个节点 CPU 或 IO 冒尖 |
| 数据分片 | 决定每一行落在哪个节点 | 分布键选错,负载一边倒 |
MPP 的核心不是节点多。是每个节点只干自己那份活。数据分得匀,并行才有意义。分得不匀,节点再多也是一个人干活,其他人等。
这里有个容易混的点。并行是一条查询拆开跑,并发是多条查询一起跑。MPP 强在并行,不代表能扛高并发。协调节点要一直接任务、拆计划、收结果。并发一高,它先成瓶颈。
MPP 数据库执行计划:一条 SQL 怎么并行跑完
一条查询在 MPP 数据库里通常五步。解析、优化、拆计划、并行执行、汇总。前两步在协调节点完成。扫描、join、聚合下沉到计算节点。
难点在“数据怎么到该去的节点”。join 常见三种走法。
| join 策略 | 怎么做 | 适合什么情况 |
|---|---|---|
| 本地 join | 两表按同一个键分布,数据已在同一节点 | 大表 join 大表,分布键就是 join 键 |
| 广播 join | 把小表复制到每个节点 | 一张表很小,另一张很大 |
| 重分布 join | 两表都按 join 键重新洗一遍 | 两张表都大,分布键对不上 |
本地 join 最省,前提是分布键和 join 键一致。这一点要在建表时想好。表建完再改,代价是搬数据。广播适合小表。小表一大,网络和内存都吃不消。
执行计划里,重分布长这样:
Gather
-> HashAggregate
-> Redistribute (city_id)
-> Seq Scan on fact_order
Redistribute 把各节点的部分结果按分组键重洗一遍。Broadcast 把小表复制到每个节点。两个动作都走网络。网络一堵,最慢节点决定整个 stage 的时长。优化器最怕两件事。统计信息不准,它估错行数。分布键选错,它算错数据在哪。
看执行计划有个简单顺序。先找 Scan,数据量大说明过滤没下推。再找 Redistribute,流量大说明分布键和 join 键对不上。最后看 Gather,它等谁,谁就是最慢节点。

金仓 KADB 走的是同一套执行模型。协调拆任务,计算节点算本地分片,重分布和广播都走网络。看执行计划判断瓶颈,方法通用。具体视图名以版本手册为准。
MPP 数据库分布键怎么选:四种分片方式与三条标准
分片方式常见四种。Hash 最常用,按 hash 值取模落节点。Range 按区间切,适合按时间增长的数据。List 按枚举分,适合地区、租户类型。复制分布每个节点存一份,只适合小维表。
Hash 匀不匀,看三件事。基数够不够高,数据匀不匀,是不是高频 join 键。三条都满足,再考虑复合键。复合键能提高均匀度。但 join 只用其中一列时,数据不一定还在同一个节点。
| 候选列 | 适合吗 | 风险 |
|---|---|---|
| 订单号这类高基数主键 | 适合 | 和 join 键不一致时仍要重分布 |
| 客户号、商户号 | 看情况 | 大客户会吸到一个节点 |
| 城市、地区、日期 | 谨慎 | 热点值造成明显倾斜 |
| 状态位、类型码 | 不适合 | 基数低,业务一偏就挤 |
分布键和分区键不是一回事。分布键决定数据去哪个节点,分区键决定数据在节点内怎么切。一个管节点之间,一个管节点之内。两个都要看,别只改一个。
选键之前,先跑数:
SELECT city_id, count(*) AS cnt
FROM fact_order
GROUP BY city_id
ORDER BY cnt DESC
LIMIT 10;
WITH dist AS (
SELECT city_id, count(*) AS cnt
FROM fact_order
GROUP BY city_id
)
SELECT
round(max(cnt)::numeric / avg(cnt), 2) AS skew_ratio,
round(max(cnt)::numeric / sum(cnt), 4) AS max_share
FROM dist;
演示表 120 万行,8 个节点。最大的城市占 62%,skew_ratio 是 18.6。8 节点的理想最大占比是 12.5%,62% 是它的五倍。看到这种数字,先查分布键,别急着改 SQL。这套判断不绑定产品,金仓 KADB 也按分布键把数据切到各节点。换的只是建表语法和系统视图名。
MPP 数据库数据倾斜怎么排查:四个原因与止血办法
数据倾斜,就是一部分数据集中在一个节点,其余节点在等。症状很典型。一个节点 CPU 或 IO 冒尖,stage 时长等于最慢节点。落盘次数变多,网络流量集中。
数据倾斜的四个原因
原因就四个。分布键基数低,热点值太大,空值太多,join 键和分布键对不上。空值和基数可以单独确认:
SELECT
count(*) FILTER (WHERE customer_id IS NULL) AS null_rows,
count(DISTINCT customer_id) AS customer_ndv
FROM sales_detail;
应急止血:加盐、条件下推与预聚合
加盐能打散热点。先按客户加随机盐做局部聚合,再去盐收口。行数少、热点不明显时,加盐反而多一层开销。
WITH partial AS (
SELECT
customer_id,
floor(random() * 16)::int AS salt,
sum(amount) AS amount
FROM sales_detail
GROUP BY customer_id, salt
)
SELECT customer_id, sum(amount)
FROM partial
GROUP BY customer_id;
暂时不能改表,先做三件事。过滤条件下推,把中间结果压小。小表广播,避免大表重分布。先局部聚合,再全局聚合,减少重分布的数据量。三招都是止血,不是治本。
四个原因不挑产品。金仓 KADB 上的处理顺序也一样。先定位热点值,再决定换键、预聚合还是加盐。换产品,换的是命令,不是思路。
周巡检 SQL 与阈值
长期稳定靠巡检。这条 SQL 我放进周任务,只看最近 7 天。
WITH dist AS (
SELECT city_id, count(*) AS cnt
FROM fact_order
WHERE order_date >= CURRENT_DATE - 7
GROUP BY city_id
)
SELECT
round(max(cnt)::numeric / avg(cnt), 2) AS skew_ratio,
round(max(cnt)::numeric / sum(cnt), 4) AS max_share
FROM dist;
阈值这么定。skew_ratio 小于 1.5、max_share 小于 15%,算正常。超过 3,或者 max_share 超过 25%,排期处理。节点越多,理想占比越低,阈值跟着调。
数据倾斜怎么治:改分布键的迁移与前后对比
数据倾斜治本的办法,多数时候是换一个更均匀的分布键。代价是搬数据。低峰期用 CTAS 建新表,灌完对账,再切视图或改表名。
CREATE TABLE fact_order_new (
LIKE fact_order INCLUDING ALL
) DISTRIBUTED BY (order_id);
INSERT INTO fact_order_new
SELECT * FROM fact_order;
ANALYZE fact_order_new;
改键前后对比
同一套演示数据,改前改后差得很明显。
| 指标 | 改前(city_id) | 改后(order_id) |
|---|---|---|
| 总耗时 | 126 秒 | 34 秒 |
| 最慢节点耗时 | 118 秒 | 31 秒 |
| 最大节点占比 | 62.0% | 13.1% |
| 落盘次数 | 3 次 | 0 次 |
迁移步骤与依赖检查
切之前把依赖查清楚。视图、物化视图、索引、外键、同步任务,一个都别漏。我漏过一个物化视图,重分布后报表空了一天,被业务追着问。
迁移顺序我一般这么走。选低峰窗口,确认同步链路能停多久。建新表,显式指定分布键。灌完对账行数和金额。跑三条典型 SQL,对比最慢节点。查完依赖,切表或切视图。观察一周,保留回滚表。步骤不复杂,难的是每一步都别省。
金仓 KADB 这类国产 MPP,迁移和运维还有一层本地化支持。改分布键、扩容、故障处理,遇到问题能找到人一起看。技术上能不能做是一回事,出问题时有没有人兜底,是另一回事。具体范围以厂商承诺为准。
MPP 数据库适合什么场景:四类负载别硬上
MPP 数据库适合大表、少并发、复杂分析。不适合的也很明确。几千 QPS 的点查,每条都要协调、拆任务、汇总,调度成本比计算还高。频繁更新和跨节点事务,代价都不低。数据量只有几十 GB,单机加索引就能扛。团队没有分布式运维经验,监控体系也没建起来,别急着上。
| 维度 | MPP 数据库 | 分布式 OLTP 数据库 | 单机数据库 |
|---|---|---|---|
| 主要负载 | 大表扫描、复杂 join、聚合 | 高并发短事务、点查 | 中小规模事务和分析 |
| 事务能力 | 跨节点事务代价高 | 强事务是核心 | 单机事务成熟 |
| 扩展方式 | 加节点、重分布数据 | 分片和副本 | 垂直扩展为主 |
| 典型场景 | 数仓、BI、报表、离线分析 | 订单、支付、账务 | 中小业务、开发测试 |
架构选型的第一原则,是匹配负载,不是追新。选之前先问自己。你的查询是等结果的交互分析,还是跑几小时的长任务。答案不一样,路线就不一样。
高并发小查询这条最容易误判。每条查询都要协调、拆任务、汇总。几千 QPS 压上去,先扛不住的是协调节点。不是 MPP 做不到,是它做这件事不划算。
MPP 数据库会被湖仓替代吗?
我的判断是,边界在融合,不是简单替代。MPP 在补联邦查询和向量化,湖仓在补 SQL 和并发。选哪个,还是看查询形态和团队。
MPP 数据库怎么选型:POC 要测的七件事
选型别只看厂商的 benchmark。拿三条最慢的业务 SQL、两张最大的表,造一份接近生产分布的数据。跑单条,跑并发,跑一次故障切换。最后看扩容一次要多久。每一步都留记录,别只看一个总耗时。
故障切换也要拆开看。正在跑的查询会不会整体失败,重试能不能只补失败的分片。扩容要问清一次多久,重分布期间线上查询会不会被拖慢。这些比峰值数字更接近生产。
| 维度 | 要问的问题 |
|---|---|
| 数据量 | 现在多大,一年后多大,单表最大多少 |
| 查询复杂度 | 多表 join、窗口函数、聚合多不多 |
| 并发 | 同时跑多少条,峰值多少 |
| 更新频率 | 批量导入还是频繁更新 |
| 事务要求 | 要不要跨节点事务,一致性要求多高 |
| 运维 | 监控、备份、扩容、故障恢复怎么做 |
| 成本 | 硬件、软件、人力、扩容怎么算 |
并发这一项最容易漏。十条大查询一起跑,会不会互相拖死。有没有资源队列、内存配额、查询优先级。这些在单条 benchmark 里看不出来,在生产里天天遇到。
金仓 KADB 可以放进 POC 清单。它的定位是分析型负载。优势在大表扫描、复杂 join 和聚合的并行处理。国产化环境里的适配和本地服务,也是它会被考虑的原因。具体版本能力以手册为准。POC 跑完,再谈选谁。
数据倾斜排查避坑清单:低基数列、平均值与依赖
先说最容易忽略的。别拿低基数列做分布键。状态位、性别、地区码,看着均匀,业务一偏就倾斜。我们有张表用 status 做键。上线三个月,大半的行挤在一个值上,查一次卡一次。
还有个习惯要改,别只看平均。平均值看着不高,可能掩盖一个接近跑满的节点。看最慢节点,看每个 stage 的耗时分布,比看总耗时有用。
改键前一定要查依赖。视图、物化视图、索引、同步链路,一个都别漏。我那次就是漏了物化视图。后来我把依赖检查写进变更单,这条坑才算堵上。
写在最后:先看数据分布,再谈扩容
三步就够用。先用 SQL 看数据落在哪。再看执行计划里有没有重分布。最后才轮到加机器。产品会换,视图名会变,判断顺序不会变。
你们现在这套 MPP,最慢节点和最快节点差多少?差得离谱的话,先别扩容,去看看分布键。
我是数据库小学妹,帮你少走弯路少踩坑,咱们下篇见👋
- 点赞
- 收藏
- 关注作者
评论(0)