由 John Doe 十一月 27, 2025
使用 COPY 加载数据到 PostgreSQL 时,单行出错会导致整个加载过程失败回滚。虽然 PostgreSQL 17 中,COPY 命令引入了 on_error 选项,但是可处理的错误还是受限的。

特性提交日志
file_fdw:为 file_fdw 新增 on_error 与 log_verbosity 选项。
在 PostgreSQL 17 版本中,COPY命令引入了on_error和log_verbosity选项。本次提交将这两个选项的支持扩展到了file_fdw(文件外部数据包装器)。
为file_fdw外部表设置on_error = 'ignore'后,即使用户查询的输入文件中包含格式错误的行,系统也会跳过这些存在问题的行,从而确保查询能够正常执行且不报错。
on_error和log_verbosity这两个选项,均适用于对file_fdw外部表执行的SELECT查询和ANALYZE操作。
讨论:https://postgr.es/m/ab59dad10490ea3734cf022b16c24cfd@oss.nttdata.com
示例
在 PostgreSQL 中,file_fdw是最常用的外部数据包装器之一,它能将本地文件(如 CSV、文本文件)挂载为数据库外部表,让用户可以通过标准 SQL 直接查询文件数据,广泛应用于日志分析、数据预览、ETL 数据抽取等场景。但在 PostgreSQL 18 之前,file_fdw存在一个明显痛点:如果外部文件中包含格式错误、数据类型不匹配的行,查询会直接报错中断,必须手动清理文件后才能重新执行,严重影响数据处理效率。
PostgreSQL 18 通过本次提交解决了这一问题,为file_fdw新增on_error和log_verbosity选项,让外部表查询具备了异常数据容错能力和日志粒度控制,大幅提升了处理外部数据的灵活性。
例如,某系统的 Nginx 访问日志按天导出为 CSV 文件,通过file_fdw挂载为外部表nginx_logs,用于实时查询访问量、热门接口等指标。但日志采集过程中,偶尔会出现个别格式错乱的行(如字段缺失、时间格式异常),导致查询直接报错。
我们需要跳过异常行,正常查询有效的日志数据,同时记录跳过的异常行数,便于后续排查问题。
1. 创建基础外部表(假设日志文件包含ip、access_time、uri、status字段):
CREATE SERVER file_server FOREIGN DATA WRAPPER file_fdw;
CREATE FOREIGN TABLE nginx_logs (
ip TEXT,
access_time TIMESTAMP,
uri TEXT,
status INT
) SERVER file_server
OPTIONS (
filename '/data/logs/nginx_20241003.csv',
format 'csv',
header 'on', -- 日志文件第一行为字段名
delimiter ','
);
2. 测试默认行为(无on_error选项):
SELECT COUNT(*) FROM nginx_logs;
ERROR: invalid input syntax for type timestamp: "2025-10-03 14:30:xx"
CONTEXT: COPY nginx_logs, line 156, column access_time: "2025-10-03 14:30:xx"
3. 添加异常处理选项:
-- 跳过错误行,保留默认日志输出(显示跳过行数)
ALTER FOREIGN TABLE nginx_logs OPTIONS (
ADD on_error 'ignore',
ADD log_verbosity 'default'
);
4. 重新执行查询:
SELECT COUNT(*) FROM nginx_logs;
NOTICE: 2 rows were skipped due to data type incompatibility
count
-------
12583
(1 row)
查询正常完成,返回有效日志总行数;通过NOTICE得知有 2 行异常数据,既不中断实时分析,也不降低数据监控质量。
file_fdw的on_error与log_verbosity特性,实现了 PostgreSQL 处理外部文件的容错能力。它让用户无需再为少量异常数据中断查询、手动清理文件,而是通过灵活的配置实现“容错执行+日志监控”,大幅提升了日志分析、数据预览、自动化 ETL 等场景的效率和稳定性。对于经常与外部文件交互的 PostgreSQL 用户来说,这是 PostgreSQL 18 中极具实用价值的一个更新。
非常不错的新特性,这样 PostgreSQL 导入数据的容错性更高了。感谢社区的所有相关人员。
参考
提交日志:https://git.postgresql.org/pg/commitdiff/a1c4c8a9e1e3a53996dafa1f4ee6d4f7de2c58b2