惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
P
Privacy International News Feed
T
Tenable Blog
L
Lohrmann on Cybersecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
S
Securelist
C
CXSECURITY Database RSS Feed - CXSecurity.com
Cisco Talos Blog
Cisco Talos Blog
T
The Exploit Database - CXSecurity.com
S
Schneier on Security
P
Privacy & Cybersecurity Law Blog
Vercel News
Vercel News
Cyberwarzone
Cyberwarzone
月光博客
月光博客
T
The Blog of Author Tim Ferriss
Scott Helme
Scott Helme
爱范儿
爱范儿
Stack Overflow Blog
Stack Overflow Blog
C
Cisco Blogs
aimingoo的专栏
aimingoo的专栏
博客园 - 司徒正美
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Proofpoint News Feed
A
Arctic Wolf
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
L
LangChain Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
阮一峰的网络日志
阮一峰的网络日志
Simon Willison's Weblog
Simon Willison's Weblog
T
Tor Project blog
Security Latest
Security Latest
Blog — PlanetScale
Blog — PlanetScale
G
GRAHAM CLULEY
V
Vulnerabilities – Threatpost
博客园 - 三生石上(FineUI控件)
I
InfoQ
Spread Privacy
Spread Privacy
B
Blog RSS Feed
Microsoft Azure Blog
Microsoft Azure Blog
S
SegmentFault 最新的问题
云风的 BLOG
云风的 BLOG
Last Week in AI
Last Week in AI
MongoDB | Blog
MongoDB | Blog
C
CERT Recently Published Vulnerability Notes
A
About on SuperTechFans
博客园_首页
Engineering at Meta
Engineering at Meta
Project Zero
Project Zero
Latest news
Latest news

博客园 - I'mAlex

Linux 环境下数据库服务开机自启实战:root.sh 脚本配置与服务管理全解 踩坑实录:NFS挂载环境下脚本执行权限问题(Operation not permitted)的深度排查与解决 单机数据库小版本升级实战:零数据迁移、分钟级完成的高效方案 表空间目录自动创建:告别手工建目录,提升数据库运维效率 配置数据库日志输出到syslog,运维再也不用挨个找日志了 一文读懂数据库data目录:原来你的数据都藏在这里 告别Oracle:深度解析数据库迁移的真实成本、技术路径与落地实战 Oracle替换实战干货:别再被迁移坑了,零改造+低成本落地全攻略 OpenClaw+优云智算Coding Plan:从灵感到成文,再到公众号发布的全流程AI自动化 MySQL迁移不再踩坑:金仓数据库兼容性与工程实力深度解析 信创替代破局:金仓数据库MySQL兼容性与迁移工程实力深度解析 融合为体,一库多能:金仓数据库重构企业数智化数据底座 KingbaseES 用户、会话与连接控制:从权限到连接池的实战运维 KingbaseES PLSQL异常处理深度解析:机制、实践与优化 国产化时序数据库替换实战:金仓全方位替代InfluxDB/TimescaleDB/TDengine指南 文档数据库国产化替代实践:金仓KES打造MongoDB高兼容迁移方案 关系数据库替换用金仓:数据迁移中的完整性与一致性风险深度解析 Oracle平滑迁移到KingbaseES关系数据库的技术实践 金仓数据库赋能北京一卡通:国产数据库在民生核心系统的信创实践标杆 深度解析数据库TOAST技术:超大字段存储的核心实现与实操指南 AI Ping实测:一站式大模型API评测+调用,开发者选型对接效率翻倍 SSH Key多密钥管理实战:不同域名/不同仓库/不同目录自动匹配不同ssh key的配置方案 KingbaseES数据库瓶颈排查实战指南:从实例到语句的全维度解析 金仓数据库平替MongoDB实操解析:多模融合赋能企业文档数据管理国产化升级
深度解析:数据库 OID 与 ROWID 原理、用法与实战避坑
I'mAlex · 2026-04-20 · via 博客园 - I'mAlex

背景

平时跟数据库打交道,OID 和 ROWID 这俩“隐藏字段”经常半路冒出来,看着很像,用起来差得不是一星半点。很多人要么把它俩混为一谈,要么只知道能用、却不知道为啥这么设计、踩过哪些坑。

本文结合实测案例,从KingbaseES的底层原理、全局 / 局部特性、创建方式、类型别名到实战坑点,完整拆解 OID 与 ROWID 的核心知识,帮你彻底分清两者边界,避开生产环境常见误用。

一、先认识 OID:数据库对象的“内部工号”

OID 就是 Object Identifier,对象标识符。你可以把它理解成数据库内部给各种对象发的唯一工号——表、函数、类型、索引、视图……全都有一个。

它是 4 字节整数,数据库内核靠它管理元数据,系统表基本都拿 OID 当主键。

1. OID 有个很关键的特点:分层生效

很多人一上来就懵:为啥有时候 OID 全局唯一,有时候又只在表里自增?

其实很简单:

  • 系统表的 OID:全局统一发号
    数据库有一个全局计数器,新建任何对象都从这里拿号。所以你新建一个类型,再建一个函数,它们的 OID 往往是连着的,跨系统表不重复。
  • 普通用户表的 OID:局部自增,每张表从头算
    这一点和 PG 不一样。在咱们常用的这款企业级数据库里,普通表即使开了 OID,也是表内独立编号,从 1 开始,不会跟别的表抢号。

2. 默认看不见,得手动“请出来”

默认建表,OID 是不存在的。你直接 select oid from 表 直接报错:列不存在。

想让表带上 OID,只有两种方式:

  • 改参数:default_with_oids = true
  • 建表时写:create table ... with oids;

开了之后它还是“隐藏列”,select * 不显示,必须手动写 oid 字段才能查出来。

3. 神器 regclass:OID 的“快捷马甲”

写系统表查询时最烦的一件事:
想查一张表的字段,得先去 sys_class 查 OID,再关联 sys_attribute

有了 regclass 就舒服多了:

-- 直接把表名转成对应 OID
select * from sys_attribute where attrelid = 'teachers'::regclass;

::regclass 本质就是 OID 的别名,相当于帮你自动执行了一次:

select oid from sys_class where relname = 'teachers';

系统表查询瞬间清爽很多,这也是日常开发里 OID 最实用的姿势。

4. OID 真不适合当业务主键

别看它能唯一标识,别拿来当业务主键用:

  • 4 字节上限大约 42.9 亿,用完会绕回来,可能重复
  • 普通表 OID 是局部的,跨表根本标识不了行
  • 不会自动建唯一索引,大量插入时冲突检测巨慢

正经做主键,用 serialbigserial 比它靠谱得多。


二、再看 ROWID:每行数据的“专属座位号”

如果说 OID 管的是对象,那 ROWID 管的就是

它是数据库给每一行记录分配的逻辑唯一标识,不是物理地址,但能做到全局唯一、快速定位,有点像 Oracle 里那味儿,但底层实现是自研逻辑。

1. ROWID 一开启,自带“VIP 索引”

ROWID 最爽的一点:
你只要 with rowid 建表,数据库自动给你建一个唯一 btree 索引

create table student(...) with rowid;

查完表结构你会看到:

Indexes:
    "student_rowid_key" UNIQUE CONSTRAINT, btree ("rowid")

查询直接按 ROWID 定位,速度极快。

2. 开启方式很灵活,但和 OID 互斥

ROWID 有三种启用姿势:

  • 开全局参数:default_with_rowid = true
  • 建表指定:with rowid
  • 已有表追加:alter table ... set with rowid;

这里有个重要规则:
ROWID 优先级 > OID
两个参数同时开,只生效 ROWID,OID 直接被屏蔽。
如果你开了 OID、想强行建 ROWID 表,数据库会直接报错阻止你,避免混乱。

3. ROWID 长什么样?一串神秘字符串

你查出来大概是这种:

AAAAAAAAADP5AAAAAAAAAAA

一共 23 个字符,用 64 进制编码(A-Z、a-z、0-9、+/),内部拆成三部分信息:

  • 事务回卷次数
  • 事务 XID
  • 事务里插入的行号

所以它是严格单调递增的:后插的行,ROWID 一定更大。

支持所有比较运算符:

select * from t where rowid > 'xxx';

排序、分组、where 条件都能用,非常丝滑。

4. 用 ROWID 要注意几件事

  • 长度必须是 23 位,多了少了都插不进去
  • 只支持大小、等于比较,不支持加减乘除
  • 支持 btree、hash 索引,别硬上其他索引类型
  • 存储过程里可以正常用,但别玩太花

三、OID vs ROWID

  • OID和ROWID对比速记图

  • OID与 ROWID详细对比
对比项 OID ROWID
管什么 数据库对象(表、函数、类型) 数据行记录
作用范围 系统表全局,普通表局部 全局逻辑唯一
数据类型 4 字节整数 23 位 64 进制字符串,变长存储
默认可见性 完全隐藏,* 不显示 隐藏,需显式查询
自动索引 自带唯一 btree 索引
开启方式 with oids / 参数开关 with rowid / 参数开关 / alter
与对方关系 优先级低,会被 ROWID 覆盖 优先级高,互斥生效
单调递增 系统表全局递增,表内从 1 开始 严格全局递增,后插更大
适合场景 系统表查询、元数据管理 快速行定位、批量处理、高效查询
风险点 42 亿后绕回,可能重复 几乎无上限,稳定性更强
业务主键建议 强烈不推荐 可用于内部快速定位,不建议业务暴露

四、顺便说一句::: 这个符号到底在干嘛?

文章里一堆 ::,比如 'teachers'::regclass'25'::integer

它就是强制类型转换,和 CAST( … AS …) 完全等价,只是写法更短。

-- 这俩效果一模一样
select '25'::integer;
select cast('25' as integer);

在系统表查询、特殊类型转换里,:: 几乎是标准写法,看着专业,写着省事。


五、总结

  • OID 是给数据库对象用的,系统表用它全局唯一,普通表开了也只是表内自增,别当业务主键。
  • ROWID 是给数据行用的,全局唯一、自带索引、查询飞快,适合快速定位行。
  • 俩东西互斥,ROWID 说了算,别同时乱开参数。
  • regclass 和 :: 是写系统 SQL 的神器,学会少写很多嵌套子查询。

整体理解下来就一句话:
OID 管对象,ROWID 管行;一个管元数据,一个管提速。