上一期说到了块-区-段-表空间,当单行数据超出数据块大小或是一个数据块空间使用很低,下次插入的时候数据又超过空余空间的时候,Oracle会如何处理。此处引出,行迁移和行链接,Oracle数据库用来处理数据块空间不足的两种机制。迁移是UPDATE触发的被动搬移(原块留指针),链接是超长行固有的分段存储(天然跨块),它们保证了数据在更新或插入时即使超出当前块空间也能成功存储,提高了数据存储的灵活性和可靠性。同样影像就是增加了I/O开销(读取一行数据需要访问多个数据块),降低了查询性能,并可能造成存储碎片。
一、行迁移与行链接的功能特点与技术原理
1. 行迁移 (Row Migration)
- 触发条件:UPDATE操作导致行长度增加,当前块剩余空间不足(即使其他块有空间)。
- 存储原理:
- 整行迁移到新块,原块保留行指针(nrid,指向新块地址)
- ROWID保持不变(查询时仍通过原ROWID定位)
- 性能影响:单行读取需访问2个块 → 逻辑I/O翻倍(如:consistent gets从2增至3)
2. 行链接 (Row Chaining)
- 触发条件:行长度超过数据块大小(如8KB块存储20KB数据)。
- 存储原理:行被拆分为多个片段(row pieces),用链表跨块存储(首块保存后续块地址)。
- 性能影响:读取单行需访问N个块(N=行长度/块大小)→ I/O呈线性增长。
3. 核心区别
|
特性 |
行迁移 |
行链接 |
|
触发时机 |
UPDATE |
INSERT或UPDATE |
|
存储形式 |
整行迁移+指针 |
行分片+链表 |
|
ROWID变化 |
不变 |
不变 |
|
首次插入是否可能 |
否 |
是 |
二、实操脚本
1. 行链接模拟与检测
-- 1. 在默认表空间建表
CREATE TABLE row_mig_demo (
id NUMBER PRIMARY KEY,
data VARCHAR2(2000)
);
--Table ROW_MIG_DEMO created.
-- 2. 插入初始数据(小数据)
INSERT INTO row_mig_demo VALUES (1, RPAD('X',2000,'Y'));
COMMIT;
--1 row inserted.
-- 3. 更新数据触发行迁移
UPDATE row_mig_demo SET data = RPAD('Y',1800,'Y') WHERE id=1;
COMMIT;
--1 row updated.
-- 4. 检测行迁移--chaintable 需要单独utl的sql
ANALYZE TABLE row_mig_demo LIST CHAINED ROWS INTO chained_rows;
SELECT owner_name, table_name, head_rowid FROM chained_rows; -- 返回迁移行
--Table ROW_MIG_DEMO analyzed.
OWNER_NAME TABLE_NAME HEAD_ROWID
_____________ _________________ _____________________
SYS ROW_CHAIN_DEMO AAATUsAAAAAAAEGAAA
-- 5. 观察I/O消耗(逻辑读从2→3)
SELECT /*+ INDEX(t) */ * FROM row_mig_demo t WHERE id=1;
ID DATA
_____ ___________________________________________________
1 YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
2. 行迁移模拟与检测
-- 1. 创建4KB块表空间
ALTER SYSTEM SET db_4k_cache_size=1m SCOPE=BOTH;
--
SYS@CDB$ROOT> alter session set container=CDB$ROOT;
Session altered.
SYS@CDB$ROOT> ALTER SYSTEM SET db_4k_cache_size=1m SCOPE=BOTH;
System altered.
--
CREATE TABLESPACE tbs_4k DATAFILE 'tbs4k.dbf' SIZE 10m BLOCKSIZE 4k;
--
SYS@CDB$ROOT> alter session set container=FREEPDB1;
Session altered.
SYS@CDB$ROOT> CREATE TABLESPACE tbs_4k DATAFILE 'tbs4k.dbf' SIZE 10m BLOCKSIZE 4k;
TABLESPACE TBS_4K created.
-- 2. 建表(设计超长行)
CREATE TABLE row_chain_demo (
id NUMBER PRIMARY KEY,
data1 CHAR(1000),
data2 CHAR(1000),
data3 CHAR(1000),
data4 CHAR(1000)
) TABLESPACE tbs_4k;
--Table ROW_CHAIN_DEMO created.
-- 3. 插入数据(触发行链接)
INSERT INTO row_chain_demo VALUES (1, 'All', 'Batch', 'Char', 'Darl');
COMMIT;
--1 row inserted.
--23ai free如果无法检测链接需要现运行utl脚本,此脚本在 SYS 模式下创建 CHAINED_ROWS 表
@?/rdbms/admin/utlchain.sql
--Table CHAINED_ROWS created.
-- 4. 检测行链接
ANALYZE TABLE row_chain_demo LIST CHAINED ROWS INTO chained_rows;
--Table ROW_CHAIN_DEMO analyzed.
SELECT owner_name, table_name, head_rowid FROM chained_rows; -- 应返回1行记录
--
OWNER_NAME TABLE_NAME HEAD_ROWID
_____________ _________________ _____________________
SYS ROW_CHAIN_DEMO AAATUsAAAAAAAEGAAA
-- 5. 观察I/O消耗(逻辑读=3)
SELECT /*+ INDEX(t) */ * FROM row_chain_demo t WHERE id=1;
SYS@CDB$ROOT> SELECT /*+ INDEX(t) */ * FROM row_chain_demo t WHERE id=1;
ID DATA1
_____ __________
1 All
三、优化策略
1. 行迁移修复
-- 重组表(消除碎片)
ALTER TABLE row_mig_demo MOVE;
--Table ROW_MIG_DEMO altered.
-- 重建索引,名字取实际index
ALTER INDEX <pk_index_name> REBUILD;
2. 行链接修复
-- 使用更大块尺寸表空间
ALTER SYSTEM SET db_32k_cache_size=20m SCOPE=BOTH;
--System altered.
CREATE TABLESPACE tbs_32k DATAFILE 'tbs32k.dbf' SIZE 20m BLOCKSIZE 32k;
ALTER TABLE row_chain_demo MOVE TABLESPACE tbs_32k;
--
SYS@CDB$ROOT> alter session set container=FREEPDB1;
Session altered.
SYS@CDB$ROOT> CREATE TABLESPACE tbs_32k DATAFILE 'tbs32k.dbf' SIZE 20m BLOCKSIZE 32k;
TABLESPACE TBS_32K created.
SYS@CDB$ROOT> ALTER TABLE row_chain_demo MOVE TABLESPACE tbs_32k;
Table ROW_CHAIN_DEMO altered.
3. 预防措施
|
问题 |
预防策略 |
|
行迁移 |
设置合理PCTFREE(如15-25%)、定期重组表、避免频繁更新大字段 |
|
行链接 |
使用CLOB/BLOB替代VARCHAR2(4000)、增大块尺寸(32KB)、压缩表 |
|
通用 |
监控字典视图:DBA_TABLES.CHAIN_CNT、DBA_TABLES.AVG_ROW_LEN |
四、官方手册上的记录,留个痕迹
行迁移定义(Oracle 19c Concepts Guide):
"When a row is updated and can no longer fit in the remaining space of the data block, Oracle moves the entire row to a new block, leaving a forwarding address in the original block."
行链接定义(Oracle 19c Concepts Guide):
"If a row is too large to fit into one block, Oracle stores the row in a chain of blocks. Row chaining occurs when a row is initially inserted."
检测方法:ANALYZE TABLE ... LIST CHAINED ROWS
实操体会:行迁移和行链接均通过破坏数据存储连续性导致I/O增加,区别在于触发机制和存储结构。通过MOVE TABLE和块尺寸优化可有效修复,合理设计表结构及参数可预防。
TIPS:生产环境操作建议在要在业务负载小的时候进行,块尺寸调整需评估内存与IO开销。
1052

被折叠的 条评论
为什么被折叠?



