Oracle 数据块结构与 PCTFREE / PCTUSED 详解
Oracle 数据块结构与 PCTFREE / PCTUSED 详解
适用版本:Oracle Database 11g / 12c / 19c / 23ai 阅读基础:了解表空间、段、区的基本概念 文档版本:v1.0 / 2026-07
目录
- 1. 概述:数据块是 I/O 的最小单位
- 2. Oracle 数据块的结构
- 3. PCTFREE 详解
- 4. PCTUSED 详解
- 5. INITRANS 与 MAXTRANS
- 6. 行迁移(Row Migration)
- 7. 行链接(Row Chaining)
- 8. 高水位线(HWM)
- 9. 相关视图与检测命令
- 10. 常见坑与排错
- 11. 最佳实践
- 12. 参考资料
1. 概述:数据块是 I/O 的最小单位
Oracle 数据库中最小的逻辑存储单位是数据块(Data Block),也是 Oracle 读写数据时最小的 I/O 单位[1]。
关键概念:
- 数据块大小:由
db_block_size参数决定(标准 8K,可选 2K/4K/8K/16K/32K) - 数据块是逻辑单位:对应 OS 层多个 OS Block(如 8K 数据块 = 16 个 512B OS Block)
- 数据块属于段:每个段(如表段、索引段)由若干数据块组成
块大小与多块大小表空间:
-- 查看数据库块大小
SHOW PARAMETER db_block_size;
-- 创建非标准块大小的表空间
ALTER SYSTEM SET db_16k_cache_size=256M SCOPE=BOTH;
CREATE TABLESPACE ts_16k
DATAFILE '/u01/oradata/orcl/ts16k_01.dbf' SIZE 1G
BLOCKSIZE 16K;
多块读参数:
-- 单次多块读最多读多少个块(受 OS 限制)
SHOW PARAMETER db_file_multiblock_read_count;
-- 默认值通常为 8 或 16
-- 8K * 16 = 128K 单次 I/O 大小
2. Oracle 数据块的结构
Oracle 数据块从结构上分为 5 个区域[1][2]:
+--------------------------------+
| Block Header (块头) | <-- 固定大小(约 100-200 字节)
| - Block Type |
| - Block Address |
| - SCN |
| - RBA |
| - ITL (Interested Transaction List) |
+--------------------------------+
| Table Directory (表目录) | <-- 聚簇表才显著
+--------------------------------+
| Row Directory (行目录) | <-- 每行 2 字节指针
+--------------------------------+
| Free Space (空闲空间) | <-- PCTFREE 控制保留量
| |
+--------------------------------+
| Row Data (行数据) | <-- 实际数据
| |
| |
+--------------------------------+
2.1 块头(Block Header)
块头是每个数据块的开头部分,存储块本身的元数据[2]:
| 元素 | 说明 | 大小 |
|---|---|---|
| Block Type | 块类型(数据/索引/Undo/临时) | 1 字节 |
| Block Address | 块地址(RDBA) | 6 字节 |
| SCN | 块的最近修改 SCN | 6 字节 |
| RBA | Redo Block Address | 8 字节 |
| ITL | Interested Transaction List(事务槽) | 每个 ~24 字节 |
| Checksum | 校验和 | 4 字节 |
ITL(Interested Transaction List):记录当前正在修改该块的事务信息,是实现行锁的基础:
ITL 0x01: XID=0x0001.012.00001234 UB=...
ITL 0x02: XID=0x0002.045.00005678 UB=...
每个 ITL 槽约 24 字节,初始数量由 INITRANS 决定,最大由 MAXTRANS 决定(19c 起 MAXTRANS 固定为 255)。
2.2 表目录(Table Directory)
记录该块中包含哪些表的数据:
- 普通表:每个数据块只属于一个表,Table Directory 只有一项
- 聚簇表(Cluster):一个数据块可包含多个表的数据,Table Directory 记录所有相关表
2.3 行目录(Row Directory)
记录块中每行的位置指针:
- 每行在 Row Directory 中占 2 字节
- 指向行数据在 Row Data 区域的偏移量
- 行被 DELETE 后,Row Directory 仍保留槽位(可重用,但不收缩)
2.4 行数据(Row Data)
实际存储行数据的地方:
- 每行包含:行头(3 字节)+ 列数 + 各列长度 + 各列值
- 列长度小于 251 字节用 1 字节存储长度,大于等于 251 字节用 3 字节
- NULL 值不占空间(仅在行尾)
2.5 空闲空间(Free Space)
块中尚未使用的空间,位于 Row Directory 和 Row Data 之间:
- 新 INSERT 在 Row Data 区域底部向上生长
- 块头和 Row Directory 从顶部向下生长
- Free Space 被两侧”夹击”
块头 ──┐
│ 向下生长(INSERT 时分配新行槽)
行目录 ──┤
│
空闲空间 │
│
│ 向上生长(INSERT 时写入新行数据)
行数据 ──┘
3. PCTFREE 详解
3.1 PCTFREE 的作用
PCTFREE 参数为每个块预留一定比例的空闲空间,用于未来 UPDATE 操作导致的行增长[1][3]。
默认值:PCTFREE = 10(即保留 10% 空间给 UPDATE)
-- 建表时指定
CREATE TABLE employees (
id NUMBER,
name VARCHAR2(100),
info CLOB
) PCTFREE 20 PCTUSED 60;
-- 修改已有表的 PCTFREE
ALTER TABLE employees PCTFREE 15;
3.2 PCTFREE 触发逻辑
当 INSERT 数据让块的空闲空间低于 PCTFREE 阈值时,该块将从**空闲列表(Free List)**中移除,不再接受新 INSERT:
假设 db_block_size=8192,PCTFREE=10:
1. 新块:8000 字节可用(扣除块头)
2. INSERT 数据直到剩余空间 ≤ 800 字节(10%)
3. 该块移出 Free List,不再接受新行
4. 仍可接受 UPDATE(剩余的 800 字节给行增长用)
PCTFREE 触发流程:
Free List 中的块:
+-------------------------------+
| Block A: free=2000B (>PCTFREE)| ── 继续接受 INSERT
| Block B: free=850B (>PCTFREE)| ── 继续接受 INSERT
| Block C: free=700B (<PCTFREE)| ── 移出 Free List(UPDATE 专用)
+-------------------------------+
3.3 PCTFREE 取值规划
| 场景 | 推荐 PCTFREE | 理由 |
|---|---|---|
| 只读表 / 历史表 | 0-5 | 不需要 UPDATE,最大化存储密度 |
| 行很少 UPDATE | 10(默认) | 平衡空间利用与扩展需求 |
| 行经常 UPDATE 增长 | 20-30 | 预留空间避免行迁移 |
| 频繁扩展的列(CLOB/BLOB) | 30-40 | 防止严重行迁移 |
估算 PCTFREE 公式:
PCTFREE = (平均 UPDATE 增长大小) / (块大小 - 块头开销) × 100
例如:块 8K,块头 200B,平均行 UPDATE 增长 800B:
PCTFREE = 800 / (8192 - 200) × 100 ≈ 10%
4. PCTUSED 详解
4.1 PCTUSED 的作用
PCTUSED 参数控制何时将块重新加入 Free List[3]:
- 当块中已用空间低于
PCTUSED阈值时,块重新加入 Free List - 配合 PCTFREE 形成”上下界”控制
默认值:PCTUSED = 40
工作机制:
PCTFREE=20 PCTUSED=40
块使用率 100% ───┐
│
│ INSERT(直到 free=PCTFREE)
│
块使用率 80% ────┼── 移出 Free List(仅允许 UPDATE)
│
│ DELETE(直到 used < PCTUSED)
│
块使用率 40% ────┘── 重新加入 Free List(接受 INSERT)
4.2 PCTFREE 与 PCTUSED 的协同
关键约束:PCTFREE + PCTUSED ≤ 100,推荐 PCTFREE + PCTUSED ≤ 80(留出缓冲)
典型组合:
| 场景 | PCTFREE | PCTUSED | 效果 |
|---|---|---|---|
| 静态表 | 5 | 85 | 最大化空间利用 |
| 平衡型 | 10 | 50 | 默认 |
| 频繁 UPDATE | 30 | 50 | 减少行迁移 |
| 高并发插入 | 10 | 30 | 减少 Free List 争用 |
注意:在**自动段空间管理(ASSM)**表空间中:
PCTUSED不再生效(由 Oracle 自动管理)PCTFREE仍然有效- ASSM 通过位图(Bitmap)管理块空间
-- 查看表空间是否使用 ASSM
SELECT tablespace_name, segment_space_management
FROM dba_tablespaces;
-- SEGMENT_SPACE_MANAGEMENT = AUTO:ASSM(忽略 PCTUSED)
-- SEGMENT_SPACE_MANAGEMENT = MANUAL:MSSM(PCTUSED 生效)
5. INITRANS 与 MAXTRANS
INITRANS 控制块头 ITL(事务槽)的初始数量,影响并发事务能力[3]:
-- 建表指定
CREATE TABLE high_concurrent_tab (
id NUMBER
) INITRANS 10 MAXTRANS 255;
-- 索引同样支持
CREATE INDEX idx_emp_dept ON employees(dept_id)
INITRANS 20 MAXTRANS 255;
| 参数 | 默认值 | 作用 |
|---|---|---|
| INITRANS(表) | 1 | 块创建时初始 ITL 槽数 |
| INITRANS(索引) | 2 | 索引块初始 ITL 槽数 |
| MAXTRANS | 255(19c 固定) | 最大 ITL 槽数 |
ITL 槽位与并发:
- 每个并发事务需要 1 个 ITL 槽
- 如果所有初始 ITL 都被占用,会从空闲空间动态分配(消耗 Free Space)
- 如果块已满,无法分配新 ITL,事务会等待 → ITL 等待(enq: TX - allocate ITL entry)
何时增大 INITRANS:
- 表并发 UPDATE 频繁
- 索引并发 INSERT 频繁
- 检测到
enq: TX - allocate ITL entry等待事件
-- 查看等待事件
SELECT event, total_waits, time_waited
FROM v$system_event
WHERE event = 'enq: TX - allocate ITL entry';
-- 修复:增大 INITRANS(仅对新建块生效,已有块需重建)
ALTER TABLE high_concurrent_tab INITRANS 20;
-- 对已有数据重建(MOVE)
ALTER TABLE high_concurrent_tab MOVE;
-- 重建索引
ALTER INDEX idx_name REBUILD ONLINE;
6. 行迁移(Row Migration)
6.1 行迁移的成因
当 UPDATE 导致行长度增长,但块中可用空间(PCTFREE 保留空间)不足以容纳新行时,整个行会被迁移到另一个块[4]:
原块(块 A):
+-------------------+
| 行 1 |
| 行 2 |
| 行 3 (已扩展) | ── 无法容纳扩展后的行
+-------------------+
迁移后:
块 A:
+-------------------+
| 行 1 |
| 行 2 |
| 行 3 (行头+指针) | ── 指向新位置
+-------------------+
块 B:
+-------------------+
| 行 3 (完整数据) | ── 实际数据存放位置
+-------------------+
6.2 行迁移的影响
- 读放大:原本 1 次 I/O 完成的查询,需要 2 次 I/O(先读原块找到指针,再读新块取数据)
- 性能下降:大量行迁移时,全表扫描性能下降明显
- 索引性能下降:索引仍指向原块,需额外跳转
6.3 检测行迁移
-- 方法 1:使用 ANALYZE 命令(旧版)
ANALYZE TABLE employees COMPUTE STATISTICS;
SELECT chain_cnt
FROM user_tables
WHERE table_name = 'EMPLOYEES';
-- 方法 2:使用 DBMS_STATS(推荐)
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'EMPLOYEES');
SELECT chain_cnt
FROM user_tables
WHERE table_name = 'EMPLOYEES';
-- 方法 3:使用 $UTLCHAIN 视图(精确分析)
ANALYZE TABLE employees LIST CHAINED ROWS;
SELECT * FROM chained_rows
WHERE table_name = 'EMPLOYEES';
6.4 修复行迁移
-- 方法 1:MOVE 表(重建所有块,需停机)
ALTER TABLE employees MOVE;
-- 重建所有索引
ALTER INDEX idx_emp_name REBUILD;
-- 方法 2:使用 CTAS 重建
CREATE TABLE employees_new AS SELECT * FROM employees;
DROP TABLE employees;
RENAME employees_new TO employees;
-- 方法 3:针对迁移行重建(在线操作)
-- 收集迁移行的 ROWID
CREATE TABLE chained_rows_temp AS
SELECT * FROM chained_rows WHERE table_name = 'EMPLOYEES';
-- 删除并重新插入迁移行
DELETE FROM employees WHERE rowid IN (SELECT head_rowid FROM chained_rows_temp);
INSERT INTO employees SELECT * FROM employees@dblink WHERE rowid IN (SELECT head_rowid FROM chained_rows_temp);
7. 行链接(Row Chaining)
7.1 行链接的成因
当一行数据本身就超过一个块的大小(如包含大 CLOB/BLOB 列),Oracle 会将这一行拆分到多个块中[4]:
块 A:
+-------------------+
| 行 1 (片 1) | ── 部分数据
| 行 2 |
| 行 3 |
+-------------------+
│
▼
块 B:
+-------------------+
| 行 1 (片 2) | ── 继续数据
+-------------------+
│
▼
块 C:
+-------------------+
| 行 1 (片 3) | ── 末尾数据
+-------------------+
7.2 行迁移 vs 行链接
| 特性 | 行迁移(Migration) | 行链接(Chaining) |
|---|---|---|
| 触发原因 | UPDATE 导致行增长 | 行本身大于块大小 |
| 数据存放 | 整行复制到新块 | 行被拆分到多块 |
| 可避免 | 是(合理 PCTFREE) | 否(除非增大块大小或拆分表) |
| 解决方法 | 重建表 + 调整 PCTFREE | 增大块大小 / 拆分 LOB 列 |
7.3 解决行链接
-- 1. 识别大行表
SELECT table_name, avg_row_len, chain_cnt
FROM user_tables
WHERE chain_cnt > 0
ORDER BY chain_cnt DESC;
-- 2. 调查大列
SELECT column_name, data_type, data_length
FROM user_tab_columns
WHERE table_name = 'LARGE_TABLE'
ORDER BY data_length DESC;
-- 3. 方案 A:将 LOB 列单独存储
ALTER TABLE large_table MOVE
LOB (lob_column) STORE AS (TABLESPACE ts_lob);
-- 4. 方案 B:使用更大的块大小表空间
CREATE TABLESPACE ts_16k DATAFILE '/u01/ts16k.dbf' SIZE 1G BLOCKSIZE 16K;
ALTER TABLE large_table MOVE TABLESPACE ts_16k;
8. 高水位线(HWM)
8.1 HWM 的概念
HWM 是段中曾经使用过的最大数据块位置:
段内块布局:
+----------+----------+----------+----------+----------+----------+
| 已使用 | 已使用 | 已使用 | 未使用 | 未使用 | 未使用 |
+----------+----------+----------+----------+----------+----------+
▲
HWM(高水位线)
- HWM 以下的块:曾经被使用,可能为空(DELETE 后)
- HWM 以上的块:从未使用过
- 全表扫描会扫描 HWM 以下所有块
8.2 HWM 的影响
- 全表扫描性能:即使表里只有 1 行,全表扫描也会扫到 HWM
- DELETE 不降低 HWM:DELETE 后 HWM 保持不变,全表扫描仍慢
- TRUNCATE 重置 HWM:TRUNCATE 将 HWM 重置为 0
8.3 降低 HWM
-- 方法 1:TRUNCATE(清空表)
TRUNCATE TABLE large_table;
-- 方法 2:MOVE 表(重建段)
ALTER TABLE large_table MOVE;
-- 方法 3:使用 SHRINK SPACE(需启用 ROW MOVEMENT)
ALTER TABLE large_table ENABLE ROW MOVEMENT;
ALTER TABLE large_table SHRINK SPACE;
-- 重建索引
ALTER INDEX idx_large REBUILD;
-- 方法 4:在线重定义(生产推荐)
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(...);
EXEC DBMS_REDEFINITION.START_REDEF_TABLE(...);
9. 相关视图与检测命令
9.1 查看表的存储参数
SELECT table_name, pct_free, pct_used, ini_trans, max_trans,
num_rows, blocks, empty_blocks, avg_space, chain_cnt
FROM user_tables
WHERE table_name = 'EMPLOYEES';
| 列 | 含义 |
|---|---|
pct_free | PCTFREE 值 |
pct_used | PCTUSED 值 |
ini_trans | INITRANS |
max_trans | MAXTRANS |
num_rows | 行数 |
blocks | 已使用块数 |
empty_blocks | HWM 下空块数 |
avg_space | 块平均空闲空间 |
chain_cnt | 链行数 |
9.2 查看数据块内容
-- 转储数据块内容(用于深度分析)
ALTER SYSTEM DUMP DATAFILE 4 BLOCK 1234;
-- 查看转储文件
-- 路径在 trace 目录下
! ls -lt $ORACLE_BASE/diag/rdbms/orcl/orcl/trace/*.trc | head
9.3 查看段空间使用情况
-- 段空间顾问
SELECT segment_name, segment_type, bytes/1024/1024 AS mb,
blocks, extents
FROM user_segments
WHERE segment_name = 'EMPLOYEES';
-- 使用 DBMS_SPACE 包查看空间使用
SET SERVEROUTPUT ON
DECLARE
l_total_blocks NUMBER;
l_total_bytes NUMBER;
l_unused_blocks NUMBER;
l_unused_bytes NUMBER;
l_last_used_extent_file_id NUMBER;
l_last_used_extent_block_id NUMBER;
l_last_used_block NUMBER;
BEGIN
DBMS_SPACE.UNUSED_SPACE(
segment_owner => USER,
segment_name => 'EMPLOYEES',
segment_type => 'TABLE',
total_blocks => l_total_blocks,
total_bytes => l_total_bytes,
unused_blocks => l_unused_blocks,
unused_bytes => l_unused_bytes,
last_used_extent_file_id => l_last_used_extent_file_id,
last_used_extent_block_id => l_last_used_extent_block_id,
last_used_block => l_last_used_block
);
DBMS_OUTPUT.PUT_LINE('Total Blocks: ' || l_total_blocks);
DBMS_OUTPUT.PUT_LINE('Unused Blocks: ' || l_unused_blocks);
END;
/
10. 常见坑与排错
10.1 大量行迁移导致查询变慢
现象:全表扫描时间从 1 秒增加到 10 秒。
排查:
SELECT chain_cnt, num_rows,
ROUND(chain_cnt/NULLIF(num_rows,0)*100, 2) AS chain_pct
FROM user_tables
WHERE table_name = 'EMPLOYEES';
-- chain_pct > 5% 需处理
修复:
-- 1. 增大 PCTFREE
ALTER TABLE employees PCTFREE 30;
-- 2. MOVE 重建表
ALTER TABLE employees MOVE;
ALTER INDEX idx_emp_id REBUILD;
10.2 enq: TX - allocate ITL entry 等待
现象:高并发场景下出现 ITL 等待。
排查:
SELECT event, total_waits, time_waited
FROM v$system_event
WHERE event = 'enq: TX - allocate ITL entry';
修复:
-- 增大 INITRANS
ALTER TABLE high_tab INITRANS 20;
-- 重建表使新参数生效
ALTER TABLE high_tab MOVE;
10.3 ORA-01653:表空间扩展失败
现象:INSERT 失败,报表空间不足。
原因:HWM 以下有大量空块(DELETE 后未释放)。
修复:
-- 1. SHRINK 表
ALTER TABLE large_tab ENABLE ROW MOVEMENT;
ALTER TABLE large_tab SHRINK SPACE;
-- 2. 或添加数据文件
ALTER TABLESPACE users ADD DATAFILE '/u02/users02.dbf' SIZE 1G;
10.4 PCTFREE 设置过低导致频繁行迁移
现象:表上 UPDATE 操作后,行迁移率持续上升。
修复:
-- 1. 评估当前迁移情况
ANALYZE TABLE emp COMPUTE STATISTICS;
SELECT chain_cnt FROM user_tables WHERE table_name='EMP';
-- 2. 增大 PCTFREE 并重建
ALTER TABLE emp PCTFREE 25;
ALTER TABLE emp MOVE;
-- 3. 重建索引
ALTER INDEX idx_emp REBUILD;
10.5 TRUNCATE 后空间未释放到 OS
现象:TRUNCATE 后表空间使用率下降,但 OS 层数据文件大小未变。
原因:TRUNCATE 重置 HWM,但数据文件大小不变(Oracle 保留空间)。
修复:
-- 缩小数据文件
ALTER DATABASE DATAFILE '/u01/users01.dbf' RESIZE 500M;
-- 或自动扩展配置
ALTER DATABASE DATAFILE '/u01/users01.dbf'
AUTOEXTEND ON NEXT 100M MAXSIZE UNLIMITED;
10.6 LOB 列导致严重行链接
现象:含 LOB 列的表 chain_cnt 极高。
修复:
-- 将 LOB 单独存放在 LOB 段
ALTER TABLE docs MOVE
LOB (content) STORE AS SECUREFILE lob_seg (
TABLESPACE ts_lob
ENABLE STORAGE IN ROW
CHUNK 8192
RETENTION
NOCACHE
);
11. 最佳实践
11.1 根据业务模式设置 PCTFREE
| 业务模式 | PCTFREE | PCTUSED |
|---|---|---|
| 日志表(INSERT only) | 5 | 85 |
| 配置表(极少 UPDATE) | 10 | 50 |
| OLTP 业务表(少量 UPDATE) | 10-20 | 50 |
| 大字段表(频繁扩展) | 30-40 | 50 |
11.2 优先使用 ASSM 表空间
-- 创建 ASSM 表空间
CREATE TABLESPACE ts_app
DATAFILE '/u01/ts_app.dbf' SIZE 1G
SEGMENT SPACE MANAGEMENT AUTO; -- ASSM
-- ASSM 优势:
-- 1. 自动管理 Free List,减少 SEGMENT 争用
-- 2. 无需手动调 PCTUSED
-- 3. 多个进程可同时 INSERT 到不同块
11.3 高并发表增大 INITRANS
-- OLTP 高并发表
CREATE TABLE order_items (
order_id NUMBER,
item_id NUMBER,
quantity NUMBER
) INITRANS 20 PCTFREE 20;
-- 索引同样配置
CREATE INDEX idx_order ON order_items(order_id) INITRANS 20;
11.4 定期监控行迁移
-- 每周检查行迁移率
SELECT table_name, chain_cnt, num_rows,
ROUND(chain_cnt/NULLIF(num_rows,0)*100, 2) AS chain_pct
FROM user_tables
WHERE num_rows > 0
AND chain_cnt > 0
ORDER BY chain_pct DESC;
-- 阈值:chain_pct > 5% 需处理
11.5 大表分区
-- 大表按时间分区,便于管理 HWM
CREATE TABLE sales (
sale_id NUMBER,
sale_date DATE,
amount NUMBER
)
PARTITION BY RANGE (sale_date) (
PARTITION p_2025_q1 VALUES LESS THAN (TO_DATE('2025-04-01','YYYY-MM-DD')),
PARTITION p_2025_q2 VALUES LESS THAN (TO_DATE('2025-07-01','YYYY-MM-DD')),
PARTITION p_2025_q3 VALUES LESS THAN (TO_DATE('2025-10-01','YYYY-MM-DD')),
PARTITION p_2025_q4 VALUES LESS THAN (TO_DATE('2026-01-01','YYYY-MM-DD'))
);
-- 历史分区可单独 TRUNCATE
ALTER TABLE sales TRUNCATE PARTITION p_2025_q1;
11.6 使用 SEGMENT 顾问
-- 自动段空间顾问
EXEC DBMS_SPACE.AUTO_SPACE_ADVISOR_JOB_PROC;
-- 查看建议
SELECT segment_name, recommendation,
space_save_estimate_mb
FROM dba_segment_advisor_recommendations
WHERE segment_owner = USER;
11.7 重建索引避免空间浪费
-- 定期重建碎片化严重的索引
SELECT index_name, height, lf_rows, del_lf_rows,
ROUND(del_lf_rows/NULLIF(lf_rows,0)*100,2) AS del_pct
FROM index_stats
WHERE del_lf_rows > 0;
-- 高度 > 3 或删除率 > 20% 需重建
ALTER INDEX idx_emp REBUILD ONLINE COMPUTE STATISTICS;
12. 参考资料
[1] Oracle Database Concepts 19c, “Logical Storage Structures” https://docs.oracle.com/en/database/oracle/oracle-database/19/cncpt/logical-storage-structures.html
[2] Oracle Database Administrator’s Guide 19c, “Managing Data Blocks” https://docs.oracle.com/en/database/oracle/oracle-database/19/admin/managing-data-blocks.html
[3] AskTOM, “PCTFREE, PCTUSED and Row Chaining Explained” https://asktom.oracle.com/pls/apex/f?p=100:1:0
[4] 墨天轮,“Oracle 数据块结构与 PCTFREE/PCTUSED 深度解析” https://www.modb.pro/db/1759656813559025664
[5] Oracle Support Note 122020.1, “Detecting and Resolving Row Chaining and Migration” https://support.oracle.com/epmos/faces/DocumentDisplay?id=122020.1
[6] Jonathan Lewis, “Oracle Core: Essential Internals for DBAs and Developers”(Apress, 2011)