【赵渝强老师】Oracle的行地址:ROWID

image

ROWID 是 Oracle 数据库伪列(pseudocolumn),每一行数据都拥有一个ROWID,但它并不是表中真实存储的字段;它代表该行在磁盘上的物理存储地址,可以快速定位一行记录。

伪列使用:可以select rowid from table;查询,不能insert/update给rowid赋值。

image.png
点击这里查看视频讲解:【赵渝强老师】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> SELECT ROWID, empno, ename, sal FROM emp WHERE empno=7839;

# 输出的信息如下:
ROWID			EMPNO ENAME	   SAL
------------------ ---------- ---------- -----
AAAR4WAAHAAAAFuAAI	 7839 KING	  5000

拆解:

  • AAAR4W:对象ID
  • AAH:相对文件号
  • AAAAFu:块号
  • AAI:块内行号

⚠️ 注意:64进制,不是16进制,不能直接当成数字阅读,Oracle内部会做转换。

2. ROWID 的重要特点

  1. 定位速度极快
    ROWID直接携带磁盘物理地址。Oracle通过ROWID访问行,不需要索引扫描,是访问单行最快方式。
-- 通过rowid直接查询,效率极高
SQL> select * from emp where rowid='AAAR4WAAHAAAAFuAAI';

# 输出的信息如下:
  EMPNO ENAME      JOB	       MGR HIREDATE    SAL  COMM     DEPTNO
------- ---------- --------- ---------- --------- ----- ----- ----------
   7839 KING       PRESIDENT 	   17-NOV-81  5000		 10
  1. 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。

  1. ROWID不是永久不变!不要作为业务主键使用
    很多人踩坑:把ROWID存到业务表当外键。当表发生move/shrink,ROWID全部变化,关联直接失效。

✔适用:临时定位数据;❌禁止做业务主键、业务外键。

  1. 区分 ROWID / UROWID
  • ROWID:普通堆表物理行地址;
  • UROWID:索引组织表(IOT)使用,是逻辑ROWID,不是物理磁盘地址。

3. 相关内置函数

3.1 dbms_rowid 包解析ROWID

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

--根据给定参数返回一个rowid ,例如
SQL> select dbms_rowid.rowid_create(0,9999,12,1000,13) from dual;

# 输出的信息如下:
DBMS_ROWID.ROWID_C
------------------
000003E8.000D.000C

4. ROWID常见使用场景

  1. DML错误数据快速定位
    导出rowid,快速定位坏数据,用于删除、修正脏数据:
delete from emp where rowid='AAAR4WAAHAAAAFuAAI';
  1. 大表更新:通过rowid批量处理,避免全表锁
-- 游标循环,根据rowid更新,分批提交
update emp set ename='xxx' where rowid=:rid;
  1. 排查行迁移、行链接问题
    结合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. 经典易错点总结

  1. ROWID是伪列,表定义看不到;
  2. update不会修改ROWID,alter table move / shrink space 会修改ROWID;
  3. 绝对不要把ROWID存储为业务字段;
  4. IOT索引组织表,要用UROWID,普通ROWID无意义;
  5. ROWID是64进制,不是16进制。
posted @ 2026-10-12 15:59  赵渝强老师  阅读(5)  评论(0)    收藏  举报