rowid加速update的本质是跳过索引与谓词计算,直接按物理地址单次i/o定位数据块;前提为已知有效rowid、配合for update加锁、避免跨事务复用,并通过order by rowid减少块反复加载。

Oracle中用 ROWID 做 UPDATE 定位,本质是跳过索引和谓词计算,直接按物理地址访问数据块——只要 ROWID 有效,就是单次 I/O 完成定位,比走索引还快。但这个“快”有严格前提:不能用于长期缓存、不能跨事务复用、不能假设稳定性。
为什么ROWID能加速UPDATE
普通 UPDATE 需先执行 WHERE 条件扫描(全表或索引查找),再定位行、加锁、修改;而用 ROWID 时,数据库直接根据 Base64 编码解析出文件号、块号、行号,一步跳转到目标数据块中的具体槽位。
- 典型场景下,
WHERE ROWID = 'AAAS5KAAFAAAABSAAA'比WHERE id = 123(即使id有索引)少一次索引块读取 + 一次回表 - 实测中,200 万行更新耗时从 16 分钟降到 6 分钟,核心收益来自
ORDER BY ROWID减少了块反复加载次数 - 但该优势仅在“已知 ROWID”的前提下成立;如果还要先
SELECT ROWID FROM ... WHERE xxx,那整体未必更快
必须配合FOR UPDATE或显式获取ROWID
直接写 UPDATE t SET x=1 WHERE ROWID IN (SELECT ROWID FROM t WHERE ...) 是无效的——Oracle 不允许子查询里引用伪列 ROWID 用于 DML 的 WHERE 子句(会报 ORA-01747)。
- 正确路径是:先用
SELECT ... ROWID FROM t WHERE ... FOR UPDATE获取带锁的ROWID集合 - 或在 PL/SQL 中用游标遍历,把
ROWID存入TABLE OF ROWID类型的集合,再用FORALL UPDATE ... WHERE ROWID = :rid -
FOR UPDATE不可省:否则并发下其他会话可能已修改或删除该行,ROWID仍有效但语义错乱
ORDER BY ROWID 能减少物理I/O次数
ROWID 编码中包含块号,按 ROWID 排序等价于按数据块物理顺序访问。这对大表批量更新很关键——避免同一块被反复读入内存又踢出。
- 示例中
SELECT ROWID FROM test ORDER BY ROWID后逐条UPDATE,比无序快 40%+,尤其在内存不足或存储 I/O 慢的环境(如虚拟机)更明显 - 但注意:排序本身有开销,若结果集小(ORDER BY;若大且需频繁更新,建议加
- 不要误以为
ORDER BY ROWID能保证业务顺序——它只优化物理访问局部性,与业务逻辑无关
ROWID不是永久地址,失效风险必须预判
ROWID 指向的是“当前时刻该行所在的物理位置”,一旦发生以下任一操作,原有 ROWID 就失效:
- 表启用行迁移(
ALTER TABLE ... ENABLE ROW MOVEMENT)后执行UPDATE导致行移动 - 执行
ALTER TABLE ... SHRINK SPACE或MOVE操作 - 分区表发生
SPLIT/EXCHANGE等 DDL - 即使没上述操作,长时间缓存
ROWID(比如存在应用层变量里超过几秒)也极不安全
真正需要稳定标识的场景,必须用业务主键或全局唯一键,而不是依赖 ROWID。











