Skip to content

PostgreSQL 常见错误码解析

错误码概述

PostgreSQL使用标准的SQL错误码,每个错误码由5个字符组成,分为两个部分:

  • 前两个字符表示错误类别
  • 后三个字符表示具体错误

错误码以"XXYYY"格式表示,例如"28000"表示认证失败。

错误码分类

1. 类00 — 成功完成

  • 00000:成功完成

2. 类01 — 警告

  • 01000:警告
  • 0100C:动态结果集返回
  • 01008:隐含类型转换
  • 01003:空值消除

3. 类02 — 无数据

  • 02000:无数据
  • 02001:未找到行

4. 类03 — 语句完成

  • 03000:语句完成

5. 类08 — 连接异常

  • 08000:连接异常
  • 08001:无法连接到服务器
  • 08003:连接不存在
  • 08004:服务器拒绝连接
  • 08006:连接失败
  • 08007:事务解析失败
  • 0800B:连接已关闭

6. 类09 — 触发器异常

  • 09000:触发器异常

7. 类0A — 特性不支持

  • 0A000:特性不支持

8. 类0B — 无效事务终止

  • 0B000:无效事务终止

9. 类0F — 无效凭证

  • 0F000:无效凭证

10. 类0L — 无效授权规范

  • 0L000:无效授权规范

11. 类0P — 无效架构名称

  • 0P000:无效架构名称

12. 类20 — 无效事务状态

  • 20000:无效事务状态
  • 20001:无效事务终止
  • 20002:无效事务状态

13. 类21 — 无效游标状态

  • 21000:无效游标状态

14. 类22 — 数据异常

  • 22000:数据异常
  • 22001:字符串数据右截断
  • 22002:空值违反非空约束
  • 22003:数值超出范围
  • 22004:空值不允许
  • 22005:错误的参数类型
  • 22007:无效的日期/时间格式
  • 22008:日期/时间溢出
  • 22009:无效的时区位移值
  • 2200B:除零错误
  • 2200D:无效的编码序列
  • 2200E:字符串长度不匹配
  • 2200F:无效的字符值
  • 22012:除零错误
  • 22015:间隔字段溢出
  • 22018:无效的字符值
  • 22019:无效的转义字符
  • 22025:无效的正则表达式
  • 22026:字符串长度不匹配
  • 22P01:无效的文本表示
  • 22P02:无效的二进制表示
  • 22P03:无效的JSON文本
  • 22P04:无效的XML文档
  • 22P05:无效的UUID
  • 22P06:无效的数组下标
  • 22P07:无效的记录下标

15. 类23 — 约束违反

  • 23000:完整性约束违反
  • 23001:限制违反
  • 23502:非空约束违反
  • 23503:外键约束违反
  • 23505:唯一约束违反
  • 23506:检查约束违反
  • 23514:排除约束违反

16. 类24 — 无效游标状态

  • 24000:无效游标状态

17. 类25 — 无效事务状态

  • 25000:无效事务状态
  • 25001:活动SQL事务中不允许操作
  • 25002:事务中不允许连接操作
  • 25003:无效的事务终止
  • 25004:事务状态无效
  • 25005:事务已提交
  • 25006:事务已回滚
  • 25007:只读SQL事务
  • 25008:事务内的原子性违反

18. 类26 — 无效SQL语句名

  • 26000:无效SQL语句名

19. 类27 — 触发器相关错误

  • 27000:触发器相关错误

20. 类28 — 无效授权规范

  • 28000:无效授权规范

21. 类2B — 依赖特权撤销

  • 2B000:依赖特权撤销

22. 类2D — 无效事务终止

  • 2D000:无效事务终止

23. 类2F — SQL函数异常

  • 2F000:SQL函数异常

24. 类34 — 无效游标名

  • 34000:无效游标名

25. 类38 — 外部例程异常

  • 38000:外部例程异常

26. 类39 — 外部例程调用异常

  • 39000:外部例程调用异常

27. 类3B — 保存点异常

  • 3B000:保存点异常

28. 类3D — 无效目录名

  • 3D000:无效目录名

29. 类3F — 无效模式名

  • 3F000:无效模式名

30. 类40 — 事务回滚

  • 40000:事务回滚
  • 40002:事务完整性约束违反
  • 40003:语句完成未知
  • 40P01:死锁检测到

31. 类42 — 语法或访问规则错误

  • 42000:语法错误或访问规则违反
  • 42001:语法错误
  • 42002:表不存在
  • 42003:列不存在
  • 42004:字段定义重复
  • 42005:对象已存在
  • 42008:WITH子句冲突
  • 42010:无效的表名
  • 42011:无效的列名
  • 42012:无效的模式名
  • 42014:无效的参数名
  • 42015:函数重定义冲突
  • 42016:约束重定义冲突
  • 42017:索引重定义冲突
  • 42018:表重定义冲突
  • 42019:数据类型重定义冲突
  • 42020:模式重定义冲突
  • 42021:视图重定义冲突
  • 42022:序列重定义冲突
  • 42023:规则重定义冲突
  • 42024:触发器重定义冲突
  • 42025:过程重定义冲突
  • 42026:类型重定义冲突
  • 42P01:表或视图不存在
  • 42P02:字段不存在
  • 42P03:未定义的函数
  • 42P04:数据库已存在
  • 42P05:数据库不存在
  • 42P06:模式已存在
  • 42P07:模式不存在
  • 42P08:关系已存在
  • 42P09:关系不存在
  • 42P10:数据类型已存在
  • 42P11:数据类型不存在
  • 42P12:操作符类已存在
  • 42P13:操作符类不存在
  • 42P14:操作符族已存在
  • 42P15:操作符族不存在
  • 42P16:聚合函数已存在
  • 42P17:聚合函数不存在
  • 42P18:排序规则已存在
  • 42P19:排序规则不存在
  • 42P20:无效的列引用
  • 42P21:无效的列定义
  • 42P22:无效的表引用

32. 类44 — 内部错误

  • 44000:内部错误

33. 类53 — insufficient_resources

  • 53000:资源不足
  • 53100:磁盘空间不足
  • 53200:内存不足
  • 53300:达到连接限制
  • 53400:配置限制超出

34. 类54 — 程序限制

  • 54000:程序限制
  • 54001:语句太长
  • 54011:列太多
  • 54023:太多参数
  • 54024:太多RETURN语句

35. 类55 — 对象状态

  • 55000:对象状态无效
  • 55001:对象正在使用中
  • 55006:对象未处于有效状态

36. 类57 — 运算符异常

  • 57000:运算符异常
  • 57014:查询超时
  • 57P01:管理员关闭了连接
  • 57P02:系统正在关闭
  • 57P03:取消请求
  • 57P04:连接丢失
  • 57P05:致命错误

37. 类58 — 系统错误

  • 58000:系统错误
  • 58030:I/O错误
  • 58P01:未定义的文件
  • 58P02:重复文件

38. 类72 — 快照太旧

  • 72000:快照太旧

39. 类F0 — 配置文件错误

  • F0000:配置文件错误

40. 类HV — 外部表错误

  • HV000:外部表错误
  • HV005:外部表未找到

41. 类P0 — PL/pgSQL错误

  • P0000:PL/pgSQL错误
  • P0001:RAISE异常
  • P0002:无数据返回
  • P0003:太多行返回

42. 类XX — 内部错误

  • XX000:内部错误
  • XX001:数据损坏
  • XX002:索引损坏

常见错误码解析与解决方案

1. 连接错误 (08000系列)

08001: 无法连接到服务器

原因

  • 服务器未运行
  • 网络连接问题
  • 防火墙阻止连接
  • 端口配置错误

解决方案

bash
# 检查服务器状态
systemctl status postgresql-14

# 检查端口是否监听
netstat -tuln | grep 5432
ss -tuln | grep 5432

# 检查防火墙设置
iptables -L -n
firewall-cmd --list-ports

# 测试网络连接
telnet hostname 5432
ping hostname

08004: 服务器拒绝连接

原因

  • 客户端IP不在允许列表中
  • 用户名或密码错误
  • 数据库不存在

解决方案

bash
# 检查pg_hba.conf配置
cat /var/lib/postgresql/14/main/pg_hba.conf

# 检查用户名和数据库是否存在
psql -U postgres -c "SELECT usename FROM pg_user;"
psql -U postgres -c "SELECT datname FROM pg_database;"

2. 数据异常 (22000系列)

22P02: 无效的二进制表示

原因

  • 尝试将无效的二进制数据转换为某种数据类型
  • 数据损坏

解决方案

sql
-- 检查数据完整性
SELECT * FROM table_name WHERE column_name::bytea IS NULL;

-- 修复损坏的数据
UPDATE table_name SET column_name = NULL WHERE column_name::bytea IS NULL;

22003: 数值超出范围

原因

  • 插入的值超过了列定义的数据类型范围
  • 计算结果溢出

解决方案

sql
-- 检查列的数据类型和范围
SELECT column_name, data_type, character_maximum_length, numeric_precision, numeric_scale
FROM information_schema.columns
WHERE table_name = 'table_name';

-- 调整数据类型或值
ALTER TABLE table_name ALTER COLUMN column_name TYPE bigint;

3. 约束违反 (23000系列)

23502: 非空约束违反

原因

  • 尝试向非空列插入NULL值
  • 列定义为NOT NULL,但插入操作未提供值

解决方案

sql
-- 检查列的约束
SELECT column_name, is_nullable, column_default
FROM information_schema.columns
WHERE table_name = 'table_name';

-- 修复插入语句,提供非空值
INSERT INTO table_name (column1, column2) VALUES (value1, value2);

-- 或修改列允许NULL
ALTER TABLE table_name ALTER COLUMN column_name DROP NOT NULL;

23503: 外键约束违反

原因

  • 尝试插入的外键值在引用表中不存在
  • 引用表中的记录被删除

解决方案

sql
-- 检查外键约束
SELECT conname, conrelid::regclass, confrelid::regclass
FROM pg_constraint
WHERE contype = 'f' AND conrelid::regclass = 'table_name'::regclass;

-- 检查引用表中是否存在对应记录
SELECT * FROM referenced_table WHERE id = foreign_key_value;

-- 修复外键值或添加对应记录
INSERT INTO referenced_table (id, ...) VALUES (foreign_key_value, ...);

23505: 唯一约束违反

原因

  • 尝试插入的记录违反了唯一约束
  • 表中已存在相同值的记录

解决方案

sql
-- 检查唯一约束
SELECT conname, conrelid::regclass, conkey::regclass[]
FROM pg_constraint
WHERE contype = 'u' AND conrelid::regclass = 'table_name'::regclass;

-- 查找重复记录
SELECT column_name, COUNT(*) 
FROM table_name 
GROUP BY column_name 
HAVING COUNT(*) > 1;

-- 修复重复记录
DELETE FROM table_name WHERE id NOT IN (SELECT MIN(id) FROM table_name GROUP BY column_name);

4. 语法或访问规则错误 (42000系列)

42P01: 表或视图不存在

原因

  • 尝试访问不存在的表或视图
  • 拼写错误
  • 模式名称错误
  • 权限不足

解决方案

sql
-- 检查表是否存在
SELECT * FROM pg_tables WHERE tablename = 'table_name';

-- 检查视图是否存在
SELECT * FROM pg_views WHERE viewname = 'view_name';

-- 检查当前模式
SHOW search_path;

-- 检查用户权限
SELECT has_table_privilege('username', 'table_name', 'SELECT');

42P02: 字段不存在

原因

  • 尝试访问不存在的列
  • 拼写错误
  • 列名大小写问题

解决方案

sql
-- 检查表的列
SELECT column_name FROM information_schema.columns WHERE table_name = 'table_name';

-- 注意PostgreSQL对大小写敏感,使用双引号引用大小写混合的列名
SELECT "Column_Name" FROM table_name;

5. 事务回滚 (40000系列)

40P01: 死锁检测到

原因

  • 两个或多个事务相互等待对方释放锁
  • 长时间运行的事务
  • 锁升级导致

解决方案

sql
-- 查看当前锁等待
SELECT * FROM pg_locks WHERE granted = false;

-- 查看锁等待链
WITH RECURSIVE lock_chain AS (
    SELECT l1.pid AS waiting_pid, l2.pid AS blocking_pid
    FROM pg_locks l1
    JOIN pg_locks l2 ON l1.locktype = l2.locktype AND l1.database = l2.database AND l1.relation = l2.relation
    WHERE l1.granted = false AND l2.granted = true
)
SELECT * FROM lock_chain;

-- 终止阻塞事务
SELECT pg_terminate_backend(pid);

-- 优化事务,减少锁定时间
-- 1. 保持事务短小
-- 2. 按相同顺序访问表
-- 3. 使用行级锁而非表级锁
-- 4. 避免长时间运行的SELECT FOR UPDATE

6. 资源不足 (53000系列)

53200: 内存不足

原因

  • 内存配置不足
  • 大量并发连接
  • 复杂查询消耗过多内存

解决方案

sql
-- 检查当前内存使用情况
SELECT * FROM pg_stat_sys_memory; -- PostgreSQL 14+

-- 检查连接数
SELECT COUNT(*) FROM pg_stat_activity;

-- 调整内存相关参数
ALTER SYSTEM SET shared_buffers = '4GB';
ALTER SYSTEM SET work_mem = '16MB';
ALTER SYSTEM SET maintenance_work_mem = '256MB';
SELECT pg_reload_conf();

-- 优化查询,减少内存使用
EXPLAIN ANALYZE SELECT * FROM large_table WHERE complex_condition;
CREATE INDEX idx_large_table_column ON large_table(column);

53100: 磁盘空间不足

原因

  • 数据文件增长过快
  • WAL日志未及时清理
  • 临时文件占用过多空间

解决方案

bash
# 检查磁盘空间
df -h

# 检查数据目录大小
du -sh /var/lib/postgresql/14/main

# 检查WAL目录大小
du -sh /var/lib/postgresql/14/main/pg_wal

# 清理WAL日志(如果复制正常)
# 确保wal_keep_size或archive_command配置正确

# 清理临时文件
rm -rf /var/lib/postgresql/14/main/pg_temp*/*

# 分析表并回收空间
VACUUM ANALYZE VERBOSE table_name;
VACUUM FULL VERBOSE table_name;  # 注意:会锁表

7. 内部错误 (XX000系列)

XX001: 数据损坏

原因

  • 硬件故障
  • 软件错误
  • 操作系统崩溃

解决方案

bash
# 检查数据完整性
pg_controldata /var/lib/postgresql/14/main

# 运行数据库检查
pg_verifybackup /path/to/backup

# 使用pg_resetwal修复(谨慎使用)
pg_resetwal -D /var/lib/postgresql/14/main -f

# 从备份恢复
pg_basebackup -D /var/lib/postgresql/14/main -c fast -Fp -Xs -v -P -U replication

错误码分析工具

1. psql命令

bash
# 查看错误码和消息
psql -U postgres -c "SELECT * FROM pg_error_codes;"

# 按类别筛选
psql -U postgres -c "SELECT * FROM pg_error_codes WHERE code LIKE '22%';"

2. pgAdmin

pgAdmin提供了图形化的错误码查询功能,可以在"工具"菜单中找到"错误码查找器"。

3. 在线资源

不同PostgreSQL版本的错误码差异

PostgreSQL 9.x

  • 错误码较少
  • 部分错误码描述不够详细
  • 缺少一些现代数据类型的错误码

PostgreSQL 10+

  • 增加了更多错误码
  • 增强了错误码描述
  • 支持更多数据类型的错误码

PostgreSQL 12+

  • 增强了JSON相关错误码
  • 增加了XML相关错误码
  • 改进了错误信息的可读性

PostgreSQL 14+

  • 增强了系统资源相关错误码
  • 增加了更多的WAL相关错误码
  • 改进了错误定位的准确性

错误处理最佳实践

1. 日志配置

ini
# 配置详细的错误日志
log_min_messages = warning
log_min_error_statement = error
log_error_verbosity = verbose
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '

2. 应用端错误处理

示例(Python)

python
import psycopg2
from psycopg2 import OperationalError, IntegrityError

try:
    conn = psycopg2.connect(
        host="hostname",
        database="database",
        user="username",
        password="password"
    )
    cur = conn.cursor()
    cur.execute("SELECT * FROM table_name")
    rows = cur.fetchall()
except OperationalError as e:
    print(f"连接错误: {e}")
except IntegrityError as e:
    print(f"完整性约束错误: {e}")
    conn.rollback()
except Exception as e:
    print(f"其他错误: {e}")
    conn.rollback()
finally:
    if conn:
        conn.close()

3. 监控和告警

  • 设置监控工具(Prometheus + Grafana)监控错误率
  • 配置告警规则,当错误率超过阈值时发送告警
  • 定期分析错误日志,识别频繁出现的错误

4. 定期维护

  • 定期运行VACUUM ANALYZE
  • 检查数据库完整性
  • 监控磁盘空间和内存使用
  • 保持PostgreSQL版本更新,获取最新的错误修复

总结

PostgreSQL错误码提供了详细的错误信息,帮助DBA快速定位和解决问题。了解常见错误码的含义和解决方案,可以提高故障处理的效率。通过合理的日志配置、应用端错误处理、监控告警和定期维护,可以减少错误的发生,提高数据库的可靠性和稳定性。