PostgreSQL列表分区恢复row too big报错排查与解决
问题解答
A. 原库为何能运行超大分区定义?
原库的分区在PostgreSQL 14.10中创建后,运行时直接读取系统元数据表(如pg_class、pg_partitioned_table)中分散存储的分区键值集合,而非以完整的VALUES列表SQL语句形式解析执行。而“row is too big”错误是在解析SQL语句阶段触发的——pg_dump导出的超长ATTACH PARTITION语句被执行时,PostgreSQL会将整个VALUES列表解析为一个临时元组,其大小超过了默认8KB的数据库块大小限制。原库运行时无需重新解析这条超长SQL,因此不会触发该错误。
B. 14.10升级到16.3未报错的原因?
PostgreSQL升级过程的核心是迁移元数据,而非重新执行分区挂载语句:
- 若使用
pg_upgrade物理升级,直接将旧版本元数据文件转换为新版本格式,全程不会触发ATTACH PARTITION语句的解析校验; - 若使用旧版本pg_dump+新版本pg_restore的逻辑升级,14.10的pg_dump导出逻辑尚未引入对超长
VALUES列表的严格校验,不会生成触发错误的语句。
总之,升级过程不会重新执行超长的ATTACH PARTITION语句,因此不会触发“row is too big”错误。
C. 如何不拆分分区完成恢复?
以下几种方法可在不拆分分区的前提下完成恢复:
使用物理备份恢复
用pg_basebackup对原库做物理备份,直接在新实例中恢复数据目录。这种方式直接迁移元数据和数据,无需执行任何ATTACH PARTITION语句,完全绕开SQL解析的大小限制。手动拆分导出的
ATTACH PARTITION语句- 用
pg_dump --section=pre-data导出元数据部分; - 打开导出的SQL文件,找到触发错误的
ALTER TABLE ... ATTACH PARTITION ... VALUES (...)语句,将超长的VALUES列表拆分为多条ATTACH PARTITION语句,每条包含部分键值(例如将10000个值拆成2条各5000个值的语句); - 先执行修改后的pre-data脚本,再用
pg_dump --section=data --section=post-data导出并恢复数据和后续配置。
注意:同一个分区可以多次执行ATTACH PARTITION添加键值,最终分区的键值集合是所有语句的并集,不会拆分分区。
- 用
临时调整SQL解析内存限制
临时增大work_mem参数(执行SET work_mem = '64MB';),部分场景下能缓解SQL解析时的内存压力,允许更长的VALUES列表通过校验。不过此方法并非百分百有效,若VALUES列表超出work_mem仍会报错。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

