由 John Doe 十月 28, 2025
你有没有需要导出 PostgreSQL 分区表的数据?现在,操作变得简单多了。

特性提交日志
支持分区表的 COPY TO 操作。
此前,COPY TO命令不支持直接指定分区表,因此用户必须使用COPY (SELECT ...) TO这种间接形式。
本次提交为分区表支持了直接使用COPY TO,同时提升了易用性与性能。性能测试表明,该方式比COPY (SELECT ...) TO更快,因为它规避了查询处理以及将结果传输至COPY TO命令的额外开销。
对分区表使用COPY TO时,其复制的行数据与执行SELECT * FROM 分区表的结果完全一致。分区表的行级安全策略会以与普通表执行COPY TO时相同的方式生效。
讨论:https://postgr.es/m/CACJufxEZt%2BG19Ors3bQUq-42-61__C%3Dy5k2wk%3DsHEFRusu7%3DiQ%40mail.gmail.com
示例
在 PostgreSQL 此前的版本中,分区表无法直接使用COPY TO命令导出数据,用户必须通过COPY (SELECT * FROM 分区表) TO的子查询方式间接实现。
若需导出按日期分区的订单表(order_parted),需手动编写子查询:COPY (SELECT * FROM order_parted) TO '/data/order_backup.csv';若忘记使用子查询,直接执行COPY order_parted TO ...会报错,提示 “cannot copy from partitioned table”,增加了学习成本与操作失误概率。
下面示例中,有一个按月份分区的订单表(order_parted),我们将全量数据导出到本地文件,用于数据备份。
创建并初始化分区表:
-- 创建按月份分区的订单表(主表)
CREATE TABLE order_parted (
order_id bigint,
user_id bigint,
order_time timestamp,
amount numeric
) PARTITION BY RANGE (order_time);
-- 创建2025年10月、11月的子分区
CREATE TABLE order_202510 PARTITION OF order_parted
FOR VALUES FROM ('2025-10-01') TO ('2025-11-01');
CREATE TABLE order_202511 PARTITION OF order_parted
FOR VALUES FROM ('2025-11-01') TO ('2025-12-01');
-- 插入测试数据(分别插入两个分区)
INSERT INTO order_parted
VALUES
(1, 1001, '2025-10-05 14:30:00', 299.99),
(2, 1002, '2025-11-10 09:15:00', 599.00);
直接使用COPY TO导出:
-- 导出全部分区数据到CSV文件
COPY order_parted TO '/data/order_backup_2025.csv' WITH (FORMAT csv, DELIMITER ',');
-- 查看导出结果(文件内容)
-- order_id,user_id,order_time,amount
-- 1,1001,"2025-10-05 14:30:00",299.99
-- 2,1002,"2025-11-10 09:15:00",599.00
对比原有的子查询方式:
COPY (SELECT * FROM order_parted) TO '/data/order_backup_old.csv' WITH (FORMAT csv);
两者导出结果完全一致,不过实际性能差别不大,导出数据的主要瓶颈还是在读写 I/O 上面。这样简化了分区表的导出方式。
非常不错的改进,感谢社区的所有相关人员。
参考
PostgreSQL 19 提交日志:https://git.postgresql.org/pg/commitdiff/4bea91f21f61d01bd40a4191a4a8c82d0959fffe