必须先执行@?/rdbms/admin/utlchain.sql创建CHAINED_ROWS表,再用ANALYZE TABLE…LIST CHAINED ROWS收集数据;CHAIN_CNT仅反映总量且需ANALYZE刷新;v$sysstat中'table fetch continued row'可实时监控跨块取行影响。

查 CHAINED_ROWS 视图前必须先创建它
直接 SELECT * FROM chained_rows 会报 ORA-00942: table or view does not exist。这不是权限问题,而是这个表根本不存在——Oracle 不自带,得手动建。
执行系统脚本创建:@?/rdbms/admin/utlchain.sql
该脚本在 SYS 用户下运行,建出 CHAINED_ROWS 表(位于 SYS schema),结构含 OWNER_NAME、TABLE_NAME、HEAD_ROWID 等字段。
常见疏漏:
- 忘记以 SYS 或具有 DBA 权限用户运行脚本
- 在非 CDB 环境误用 @?/cdb/rdbms/... 路径(路径错会导致脚本找不到)
- 创建后未提交,导致后续 ANALYZE 写不进数据
用 ANALYZE TABLE ... LIST CHAINED ROWS 收集数据
ANALYZE 是唯一能区分迁移与链接并写入 CHAINED_ROWS 的命令;DBMS_STATS.GATHER_TABLE_STATS 完全不检测这两类问题。
执行方式:ANALYZE TABLE scott.emp LIST CHAINED ROWS INTO chained_rows;
注意点:
- 表需处于非只读状态,且无 DML 正在修改该表(否则可能报 ORA-00054)
- 若表有主外键依赖,建议先 DISABLE 外键约束,分析完再 ENABLE(否则部分行可能跳过)
- INTO chained_rows 必须显式指定,不能省略或写错表名
- 该操作会持有一个表级共享锁,高并发 OLTP 表慎在业务高峰执行
从 USER_TABLES.CHAIN_CNT 快速看总量
如果只想知道“有没有问题”,不用定位具体行,查数据字典更快:SELECT table_name, chain_cnt FROM user_tables WHERE chain_cnt > 0;
但要注意:
- CHAIN_CNT 是行迁移 + 行链接的**总和**,无法拆开
- 这个值不会实时更新,需先执行 ANALYZE 或 DBMS_STATS.GATHER_TABLE_STATS(后者只更新统计信息,不刷新 CHAIN_CNT;真正刷 CHAIN_CNT 的仍是 ANALYZE)
- 对于大表,ANALYZE 可能很慢,而 CHAIN_CNT 查起来秒出,适合巡检脚本
用 v$sysstat 监控运行时影响
如果怀疑迁移/链接正在拖慢 SQL,别只盯历史数据,看实时等待:SELECT name, value FROM v$sysstat WHERE name = 'table fetch continued row';
这个计数器每发生一次跨块取行(无论迁移还是链接),就 +1。持续上涨说明应用正在受其影响。
关键细节:
- 它是实例级累计值,不是会话级,所以要对比前后差值才有意义
- 单次查询返回 0 不代表没发生,可能是刚清空过或还没触发
- 和 CHAINED_ROWS 不同,它不告诉你哪张表,只告诉你“有这回事”——得结合 AWR 或 SQL Monitor 定位到具体语句再反查对象
真正麻烦的是:你查到了迁移或链接行,但 HEAD_ROWID 指向的是“首块地址”,而迁移行的原块和新块、链接行的各分片块,都得靠 DBMS_ROWID 解析或 ALTER SYSTEM DUMP DATAFILE 才能确认物理分布——那一步才是调优的深水区。


















