PostgreSQL 分区表排序优化:Append Sort 优化为 Merge Append

最近在优化一个 PostgreSQL 查询时,遇到一个典型的 分区表排序性能问题,通过索引重构和执行计划分析,,优化效果非常明显,记录一下完整过程。


一、问题背景

业务中有一张 按状态分区的表

复制代码
order_partitioned_table
├── partition_active      (status = 0)
└── partition_archive     (default)

查询 SQL 如下:

复制代码
SELECT user_id, object_id
FROM order_partitioned_table
WHERE status IN (0, 22)
  AND expire_time < ?
ORDER BY expire_time ASC, object_id ASC;

该查询返回 60W+ 行数据,执行计划如下:

复制代码
Append
  -> Index Scan partition_active
  -> Index Scan partition_archive
Sort

执行时间:

复制代码
Execution Time: 53s

明显瓶颈在:

复制代码
Append + Sort

二、为什么会慢?

执行流程是:

  1. 扫描 partition_active

  2. 扫描 partition_archive

  3. 拼接结果 (Append)

  4. 对 60W 行整体排序 (Sort)

也就是:

复制代码
Append
   ↓
Sort (600k rows)

这种模式的问题:

  • 排序数据量大

  • CPU 消耗高

  • 内存消耗大

  • 可能发生磁盘排序


三、理想执行计划

我们希望变成:

复制代码
Merge Append

而不是:

复制代码
Append + Sort

为什么?

Append + Sort

相当于:

  1. 两堆乱序数据合并

  2. 再整体排序

复杂度:

复制代码
O(N log N)

Merge Append

前提:

两个子查询 已经有序

然后:

复制代码
归并排序

复杂度:

复制代码
O(N)

这就是优化核心。


四、优化思路

关键点:

每个分区本身就按 ORDER BY 顺序输出

ORDER BY:

复制代码
expire_time, object_id

因此索引必须:

复制代码
(expire_time, object_id)

并且:

复制代码
WHERE status IN (0,22)

因此采用 Partial Index


五、最终优化索引

Active 分区

复制代码
CREATE INDEX CONCURRENTLY partition_active_exp_idx
ON partition_active (expire_time, object_id, user_id)
WHERE status IN (0, 22);

Archive 分区

复制代码
CREATE INDEX CONCURRENTLY partition_archive_exp_idx
ON partition_archive (expire_time, object_id, user_id)
WHERE status IN (0, 22);

六、优化后的执行计划

复制代码
Merge Append
   -> Index Only Scan partition_active
   -> Index Only Scan partition_archive

执行时间:

复制代码
Execution Time: 559 ms

优化效果:

阶段 执行时间
初始 53s
优化后 0.55s

提升:

复制代码
≈ 100x 性能提升

七、为什么 Partial Index 更适合

原索引:

复制代码
(status, user_id, expire_time, ...)

问题:

  • status 放在前面破坏排序

  • 无法使用 Merge Append

而 Partial Index:

复制代码
(expire_time, object_id)
WHERE status IN (0,22)

优势:

  • 索引更小

  • 顺序更符合 ORDER BY

  • 更容易触发 Merge Append


八、Merge Append vs Append + Sort

Append + Sort

流程:

复制代码
partition_active
partition_archive
      ↓
    Append
      ↓
     Sort

需要:

  • 全量排序

  • 大内存

  • CPU 高


Merge Append

流程:

复制代码
partition_active (ordered)
partition_archive (ordered)
      ↓
   Merge Append

优势:

  • 不需要整体排序

  • 只做归并

  • 更快更稳定


九、PostgreSQL 版本注意事项

该优化在 PostgreSQL 14 测试通过。

PostgreSQL 14 对分区优化能力相比 15/16 略弱,因此:

  • 索引顺序尤为重要

  • Partial Index 更容易触发 Merge Append

在 PostgreSQL 15+ 中,该优化效果通常更明显。


十、总结

本次优化关键点:

  1. 避免 Append + Sort

  2. 让每个分区按排序键输出

  3. 使用 Partial Index

  4. 触发 Merge Append

最终实现:

复制代码
53s → 559ms

分区表排序优化,核心就是:

让每个分区先排好,再合并,而不是先合并再排序


如果你也遇到 PostgreSQL 分区表排序慢的问题,这种思路通常非常有效。


相关推荐
Q26433650234 小时前
【有源码】基于 Hadoop 生态的化妆品销售数据存储分析与可视化 面向化妆品行业的用户画像构建与销售机会识别研究
大数据·hadoop·python·机器学习·spark·毕业设计·课程设计
2601_9622186110 小时前
万象生鲜系统业财一体化底层打通技术自动生成经营账单
大数据·数据库·人工智能·python·算法
李高钢10 小时前
Python FastAPI 框架入门:从零搭建你的第一个高性能 API 服务
数据库·python·fastapi
Easy_API11 小时前
从“有多少卡“到“卖多少 Token“:算力的标尺正在换
大数据·人工智能·深度学习
移动云开发者联盟12 小时前
中国移动发布全链条算力服务成果
大数据
yuzhiboyouye12 小时前
那xml对应的sql语法,列举一下
xml·数据库·sql
晓窗科技12 小时前
口碑好的AI基座服务商
大数据·人工智能·python
和裕12 小时前
蜂窝板 vs 七层瓦楞重型纸箱:大件工业设备运输性能与成本全对比
大数据·运维·网络·人工智能·算法
. . . . .12 小时前
乐观锁 vs 悲观锁
数据库·sql
ACP广源盛1392462567312 小时前
国产 PCIe2.1 交换芯片 IX6024:低成本轻量化端侧 AI IO 扩展选型解析
大数据·人工智能·硬件架构·pcie·国产芯片