
ROWID 是 Oracle 数据库伪列(pseudocolumn) ,每一行数据都拥有一个ROWID,但它并不是表中真实存储的字段;它代表该行在磁盘上的物理存储地址,可以快速定位一行记录。
伪列使用:可以
select rowid from table;查询,不能insert/update给rowid赋值。
| 视频讲解如下 |
|---|
| 【赵渝强老师】Oracle的行地址:ROWID |
1. ROWID 格式(物理ROWID,10g及以后扩展ROWID)
Oracle 扩展ROWID一共18位字符 ,由64进制字符组成(A‑Z,a‑z,0‑9,+,/)。
格式:
OOOOOOFFFBBBBBBRRR
对象号|文件号|块号 |行号
| 片段 | 长度 | 含义 |
|---|---|---|
OOOOOO |
6位 | 数据对象编号(Data Object Number),标识段(表/索引等) |
FFF |
3位 | 相对文件号(Relative File Number),表空间内的数据文件编号 |
BBBBBB |
6位 | 数据块号(Block Number),该文件内的数据块编号 |
RRR |
3位 | 块内行号(Row Number),数据块内部,行的槽位号(从0开始) |
示例:
sql
SQL> SELECT ROWID, empno, ename, sal FROM emp WHERE empno=7839;
# 输出的信息如下:
ROWID EMPNO ENAME SAL
------------------ ---------- ---------- -----
AAAR4WAAHAAAAFuAAI 7839 KING 5000
拆解:
AAAR4W:对象IDAAH:相对文件号AAAAFu:块号AAI:块内行号
⚠️ 注意:64进制,不是16进制,不能直接当成数字阅读,Oracle内部会做转换。
2. ROWID 的重要特点
- 定位速度极快
ROWID直接携带磁盘物理地址。Oracle通过ROWID访问行,不需要索引扫描,是访问单行最快方式。
sql
-- 通过rowid直接查询,效率极高
SQL> select * from emp where rowid='AAAR4WAAHAAAAFuAAI';
# 输出的信息如下:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
------- ---------- --------- ---------- --------- ----- ----- ----------
7839 KING PRESIDENT 17-NOV-81 5000 10
- ROWID什么时候会变化?
DELETE + INSERT:旧行删除,插入新行 → ROWID改变UPDATE:普通update不改rowid ;但如果更新导致行迁移(row migration)、行链接(row chaining),行移动到别的块,ROWID不变!只是指针指向新位置ALTER TABLE ... MOVE表迁移、表收缩shrink、exp/imp导入导出、分区表move分区:ROWID会发生改变
❗重点:
UPDATE不会改变ROWID;MOVE、shrink会改变ROWID。
- ROWID不是永久不变!不要作为业务主键使用
很多人踩坑:把ROWID存到业务表当外键。当表发生move/shrink,ROWID全部变化,关联直接失效。
✔适用:临时定位数据;❌禁止做业务主键、业务外键。
- 区分 ROWID / UROWID
ROWID:普通堆表物理行地址;UROWID:索引组织表(IOT)使用,是逻辑ROWID,不是物理磁盘地址。

3. 相关内置函数
3.1 dbms_rowid 包解析ROWID
sql
SQL> SELECT
ROWID,
dbms_rowid.rowid_object(ROWID) 对象号,
dbms_rowid.rowid_relative_fno(ROWID) 相对文件号,
dbms_rowid.rowid_block_number(ROWID) 块号,
dbms_rowid.rowid_row_number(ROWID) 块内行号
FROM emp;
# 输出的信息如下:
ROWID 对象号 相对文件号 块号 块内行号
------------------ ---------- --------------- ---------- ------------
AAAR4WAAHAAAAFuAAA 73238 7 366 0
AAAR4WAAHAAAAFuAAB 73238 7 366 1
AAAR4WAAHAAAAFuAAC 73238 7 366 2
AAAR4WAAHAAAAFuAAD 73238 7 366 3
AAAR4WAAHAAAAFuAAE 73238 7 366 4
AAAR4WAAHAAAAFuAAF 73238 7 366 5
AAAR4WAAHAAAAFuAAG 73238 7 366 6
AAAR4WAAHAAAAFuAAH 73238 7 366 7
AAAR4WAAHAAAAFuAAI 73238 7 366 8
AAAR4WAAHAAAAFuAAJ 73238 7 366 9
AAAR4WAAHAAAAFuAAK 73238 7 366 10
AAAR4WAAHAAAAFuAAL 73238 7 366 11
AAAR4WAAHAAAAFuAAM 73238 7 366 12
AAAR4WAAHAAAAFuAAN 73238 7 366 13
14 rows selected.
| 函数 | 功能 |
|---|---|
dbms_rowid.rowid_object(rowid) |
获取数据对象ID |
dbms_rowid.rowid_relative_fno(rowid) |
获取相对文件号 |
dbms_rowid.rowid_block_number(rowid) |
获取数据块号 |
dbms_rowid.rowid_row_number(rowid) |
获取块内行槽号 |
3.2 根据编号反向生成ROWID
sql
--根据给定参数返回一个rowid ,例如
SQL> select dbms_rowid.rowid_create(0,9999,12,1000,13) from dual;
# 输出的信息如下:
DBMS_ROWID.ROWID_C
------------------
000003E8.000D.000C
4. ROWID常见使用场景
- DML错误数据快速定位
导出rowid,快速定位坏数据,用于删除、修正脏数据:
sql
delete from emp where rowid='AAAR4WAAHAAAAFuAAI';
- 大表更新:通过rowid批量处理,避免全表锁
sql
-- 游标循环,根据rowid更新,分批提交
update emp set ename='xxx' where rowid=:rid;
- 排查行迁移、行链接问题
结合dbms_rowid拿到block、file,dump数据块查看存储。
5. 与 openGauss / MySQL 的对比
- Oracle:ROWID伪列,物理地址;
- MySQL InnoDB:没有rowid伪列 ,用聚簇索引主键定位行;隐藏列
DB_ROW_ID仅当表无主键时内部使用; - openGauss(PG):伪列
ctid,格式(块号,槽号),作用类似Oracle ROWID。
openGauss ctid示例:
(0,1),代表第0号块,第1号槽位。ctid也会VACUUM、update时发生变化,不能做业务主键。
6. 经典易错点总结
- ROWID是伪列,表定义看不到;
- update不会修改ROWID,
alter table move/ shrink space 会修改ROWID; - 绝对不要把ROWID存储为业务字段;
- IOT索引组织表,要用UROWID,普通ROWID无意义;
- ROWID是64进制,不是16进制。
