首页/数据/SQL 速查/分表结果合并统计

分表结果合并统计

按时间或业务分表后,用 UNION ALL 合并各分片再聚合;列结构必须一致,聚合放在合并之后。

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

分表结果合并统计

按时间或业务把数据拆成多张表之后,跨分片的汇总统计要靠合并:把各个分片的结果用不去重的合并拼成一张逻辑表,再在外层做分组聚合。有两个必须守住的前提:各分支的列数与顺序要一致、类型要兼容;聚合必须发生在合并之后,否则平均值、去重计数这类指标算出来的口径是错的。

基本信息

适用平台MySQL 8.0 / PostgreSQL 12 及以上
合并方式不去重的合并保留全部分片行,适合统计
结构要求分支列数一致、顺序对应、类型可兼容
聚合位置必须放在合并后的外层
分片建议命名带时间后缀,便于拼接与后续归档

典型使用场景

  • 按月分表的订单表做年度汇总统计
  • 按业务线分库的数据合并成统一报表
  • 分片数据做去重计数:必须整体去重后再计数
  • 历史分片归档前的核对:合并后行数与预期比对
  • 跨分片的平均值计算:不能对各分片平均值再求平均

合并与聚合示例

合并与聚合示例
-- 先把分片拼成逻辑表,再在外层聚合
SELECT city, SUM(amount) AS total, COUNT(*) AS cnt
FROM (
    SELECT city, amount FROM orders_2023
    UNION ALL
    SELECT city, amount FROM orders_2024
) t
GROUP BY city
ORDER BY total DESC;

-- 分片类型不一致时显式对齐,避免隐式转换
-- SELECT city, CAST(amount AS DECIMAL(18,2)) FROM orders_2023

-- 跨分片求平均:用总量除以总行数,不要对分片平均值再平均
SELECT SUM(total) / SUM(cnt) AS avg_amount
FROM (
    SELECT SUM(amount) AS total, COUNT(*) AS cnt FROM orders_2023
    UNION ALL
    SELECT SUM(amount) AS total, COUNT(*) AS cnt FROM orders_2024
) s;

-- 跨分片去重计数:先合并再整体去重
SELECT COUNT(DISTINCT user_id)
FROM (SELECT user_id FROM orders_2023
      UNION ALL
      SELECT user_id FROM orders_2024) u;

分片合并要点

关注点做法常见错误
列结构列数与顺序对齐,类型显式转换依赖隐式转换,取值被截断
行合并使用不去重形式保留全部分片行用去重形式导致重复数据被合并
聚合位置合并之后在外层聚合先聚合再合并,口径错误
平均值总量除以总行数对分片平均值再求平均
去重计数先合并再整体去重把分片去重结果相加
平均值的错误最隐蔽:对各分片的平均值再求平均,得到的是一个与真实平均无关的数字,而且量级看起来很正常。分片行数差异越大,偏差越离谱。
分片数量经常增长时,手工拼接的合并语句会越来越难维护。可以考虑用视图把分片统一暴露成一张逻辑表,业务查询只针对视图编写。

易错点

  • 先聚合再合并,指标口径错误且不易发现,尤其是平均值与去重计数
  • 分片列类型不一致(整数与长整数、不同精度小数)触发隐式转换,比较与汇总结果失真
  • 用去重的合并形式统计分片数据,重复业务行被合并,总数偏小
  • 分片列顺序不一致导致取值错位,语句不报错但结果全错
  • 分片数量增长后语句未同步更新,新分片的数据被整段漏掉

数据来源与参考

  • MySQL 8.0 Reference Manual · UNION
  • PostgreSQL Documentation · UNION
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌