对象标识符类型
PostgreSQL 使用对象标识符(OID)在系统目录中标识表、类型、函数等数据库对象。常见的 OID 相关类型包括 oid、regclass、regtype、regproc 和 regprocedure。它们主要用于系统管理、元数据查询和动态 SQL 辅助,不适合作为业务主键。
oid 与系统目录
SELECT oid, relname, relkind
FROM pg_class
WHERE relname = 'users';
OID 在一个数据库集群内部标识对象,可能在导出、恢复、重建或跨数据库迁移后改变。表行的 ctid、事务 ID 等内部标识也有类似的生命周期限制。
注册类型:把名称解析为 OID
SELECT 'public.users'::regclass;
SELECT 'jsonb'::regtype;
SELECT 'public.my_function(integer)'::regprocedure;
regclass 等类型会根据当前搜索路径和对象可见性把名称解析为对应 OID。反向转换为文本时,PostgreSQL 通常会输出足以唯一识别对象的带引号名称。
使用 regclass 可以避免手工查询 pg_class 后再拼接 OID:
SELECT 'public.users'::regclass::oid;
搜索路径和安全
未限定模式的对象名会受 search_path 影响。安全敏感的函数、迁移和管理脚本应显式限定模式,并控制 search_path,避免恶意对象遮蔽预期名称。
不要把用户提供的字符串直接转换为 regclass 后执行动态 SQL;先使用白名单映射到允许的对象,必要时用 format('%I', identifier) 正确引用标识符。
与业务 ID 的区别
业务主键应使用稳定、可迁移、可由业务控制的类型,例如 bigint 或 uuid。OID:
- 只在特定数据库对象上下文中有意义;
- 可能因备份恢复、逻辑复制或迁移而改变;
- 对普通表行并非天然唯一;
- 暴露内部结构,可能增加信息泄露风险。
系统目录中的 OID 可以作为诊断信息记录,但不应写入面向用户的永久引用。
常见误区
- 用 OID 作为订单、用户或文件的业务主键。
- 认为不同数据库中的同一个 OID 代表同一个对象。
- 忽略
search_path,让未限定名称解析到错误对象。 - 把
regclass文本转换当成无害字符串操作,未做白名单和权限检查。 - 依赖系统目录内部字段,却没有按 PostgreSQL 版本验证。