Oracle 区(Extent)分配策略与高水位线
Oracle 区(Extent)分配策略与高水位线
适用版本:Oracle Database 11g / 12c / 19c / 23ai 文档版本:v1.0 / 2026-07
1. 概述
区(Extent) 是 Oracle 分配空间的基本单位,由连续的数据块组成[1]:
Segment
├── Extent 1 (blocks 1-16) ← 初始 extent
├── Extent 2 (blocks 17-32) ← 第 2 个 extent
├── Extent 3 (blocks 33-64) ← 第 3 个 extent(更大)
└── ...
高水位线(HWM, High Water Mark) 标识段中曾经使用过的最大数据块位置。
2. EXTENT 分配策略
2.1 字典管理(Dictionary Managed)
旧版方式,已弃用:
-- 不推荐
CREATE TABLESPACE ts_dict
DATAFILE '/u01/ts.dbf' SIZE 1G
EXTENT MANAGEMENT DICTIONARY;
2.2 本地管理(Locally Managed)
11g+ 默认,性能更好[1]:
CREATE TABLESPACE ts_local
DATAFILE '/u01/ts.dbf' SIZE 1G
EXTENT MANAGEMENT LOCAL;
-- AUTOALLOCATE 或 UNIFORM SIZE
2.3 AUTOALLOCATE vs UNIFORM SIZE
| 策略 | 行为 | 适用 |
|---|---|---|
| AUTOALLOCATE | Oracle 自动调整大小(默认 64K→1M→8M→64M) | 通用 |
| UNIFORM SIZE | 所有 extent 相同大小 | 数据仓库、控制碎片 |
-- AUTOALLOCATE(默认)
CREATE TABLESPACE ts_auto
DATAFILE '/u01/ts.dbf' SIZE 1G
EXTENT MANAGEMENT LOCAL AUTOALLOCATE;
-- UNIFORM SIZE
CREATE TABLESPACE ts_uniform
DATAFILE '/u01/ts.dbf' SIZE 1G
EXTENT MANAGEMENT LOCAL UNIFORM SIZE 4M;
2.4 AUTOALLOCATE 增长策略
Extent 1: 64K
Extent 2: 64K
Extent 3: 64K
Extent 4: 64K
Extent 5-15: 1M
Extent 16-79: 8M
Extent 80-199: 64M
Extent 200+: 64M
→ 段越大,extent 越大,减少分配次数
2.5 查看段 extent
SELECT
segment_name,
extent_id,
bytes/1024/1024 AS mb,
blocks
FROM dba_extents
WHERE owner=USER AND segment_name='EMPLOYEES'
ORDER BY extent_id;
3. 高水位线(HWM)
3.1 HWM 概念
段内块布局:
+----+----+----+----+----+----+----+----+----+----+----+----+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
+----+----+----+----+----+----+----+----+----+----+----+----+
↑ ↑
原 HWM 当前 HWM
块 1-8:曾经使用过
块 9-10:DELETE 后空闲但 HWM 下
块 11-12:从未使用,HWM 上
3.2 HWM 的影响
- 全表扫描扫到 HWM:即使块空也扫
- DELETE 不降低 HWM:仅 TRUNCATE 重置
- 影响查询性能:大量空块导致全表扫描慢
3.3 查看 HWM
-- 查看表的块使用情况
SELECT
table_name,
num_rows,
blocks,
empty_blocks,
avg_space,
chain_cnt
FROM user_tables
WHERE table_name='EMPLOYEES';
-- 块统计
ANALYZE TABLE employees COMPUTE STATISTICS;
-- 或
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'EMPLOYEES');
3.4 查看实际使用 vs HWM
-- 实际使用块数(通过 dba_tables)
SELECT blocks AS hwm_blocks FROM user_tables WHERE table_name='EMPLOYEES';
-- 实际有数据的块数
SELECT COUNT(DISTINCT dbms_rowid.rowid_block_number(rowid)) AS used_blocks
FROM employees;
-- 比较
-- hwm_blocks - used_blocks = 浪费的扫描块
4. 低 HWM 与高 HWM
11g+ 引入两个 HWM:
+----+----+----+----+----+----+----+----+----+----+
| D | D | D | D | U | U | U | U | U | U |
+----+----+----+----+----+----+----+----+----+----+
↑ ↑
低 HWM 高 HWM
D = 数据已写入
U = 未写入
全表扫描:
- 高 HWM 以下:扫描所有块
- 低 HWM 以下:所有块都有数据
- 低 HWM 到高 HWM:可能有数据,需检查块状态
5. 降低 HWM 的方法
5.1 TRUNCATE(最彻底)
-- 重置 HWM 为 0
TRUNCATE TABLE large_table;
-- 数据全部清除,HWM 归零
5.2 ALTER TABLE MOVE
-- 重建段,HWM 降至实际大小
ALTER TABLE large_table MOVE;
-- 重建所有索引(MOVE 会导致索引失效)
ALTER INDEX idx_name REBUILD;
5.3 SHRINK SPACE(在线操作)
-- 1. 启用行移动
ALTER TABLE large_table ENABLE ROW MOVEMENT;
-- 2. SHRINK
ALTER TABLE large_table SHRINK SPACE;
-- HWM 降低,索引自动维护
-- 3. 仅紧凑不降 HWM
ALTER TABLE large_table SHRINK SPACE COMPACT;
5.4 在线重定义
-- 生产环境推荐
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(USER, 'LARGE_TABLE');
EXEC DBMS_REDEFINITION.START_REDEF_TABLE(USER, 'LARGE_TABLE', 'LARGE_TABLE_NEW');
-- 中间同步
EXEC DBMS_REDEFINITION.SYNC_INTERIM_TABLE(USER, 'LARGE_TABLE', 'LARGE_TABLE_NEW');
EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE(USER, 'LARGE_TABLE', 'LARGE_TABLE_NEW');
6. EXTENT 分配与回收
6.1 分配新 EXTENT
-- 手动分配
ALTER TABLE employees ALLOCATE EXTENT;
-- 或指定大小
ALTER TABLE employees ALLOCATE EXTENT (SIZE 10M);
-- 自动分配触发条件:
-- INSERT 时现有 extent 已满
6.2 释放 EXTENT
-- 释放 HWM 上的空闲 extent
ALTER TABLE employees DEALLOCATE UNUSED;
-- 指定保留大小
ALTER TABLE employees DEALLOCATE UNUSED KEEP 100M;
6.3 段空间顾问
-- 自动 segment advisor
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;
7. 常见坑与排错
7.1 DELETE 后查询变慢
现象:DELETE 大量数据后,全表扫描反而变慢。
原因:DELETE 不降低 HWM。
修复:
-- 1. SHRINK SPACE
ALTER TABLE large_tab ENABLE ROW MOVEMENT;
ALTER TABLE large_tab SHRINK SPACE;
-- 2. 或使用分区表
7.2 TRUNCATE 后空间未释放
现象:TRUNCATE 后数据文件大小不变。
原因:TRUNCATE 重置 HWM,但数据文件不缩小。
修复:
-- 缩小数据文件
ALTER DATABASE DATAFILE '/u01/users01.dbf' RESIZE 500M;
7.3 表空间碎片
现象:表空间有大量碎片,新 extent 难以分配。
修复:
-- 使用本地管理表空间
-- 使用 ASSM
-- 定期 SHRINK 或 MOVE 表
-- 查看碎片
SELECT
tablespace_name,
COUNT(*) AS free_extents,
SUM(bytes)/1024/1024 AS free_mb
FROM dba_free_space
GROUP BY tablespace_name;
7.4 SHRINK 失败
现象:ORA-10631: SHRINK clause cannot be executed on this segment。
原因:段上有约束或触发器限制。
修复:
-- 1. 检查约束
SELECT constraint_name, constraint_type
FROM user_constraints
WHERE table_name='LARGE_TAB';
-- 2. 使用 MOVE 代替
ALTER TABLE large_tab MOVE;
8. 最佳实践
- 使用本地管理表空间:性能优于字典管理
- 大表用 AUTOALLOCATE:自动调整 extent 大小
- 数据仓库用 UNIFORM SIZE:减少碎片
- 大表分区:便于管理 HWM
- DELETE 后 SHRINK:降低 HWM
- TRUNCATE 优于 DELETE:清空表用 TRUNCATE
- 历史数据归档:使用分区交换
- 定期运行 Segment Advisor:识别优化机会
- HWM 监控:
blocks - used_blocks比例高时处理 - 生产用在线重定义:避免停机
9. 参考资料
[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 Segments” https://docs.oracle.com/en/database/oracle/oracle-database/19/admin/managing-segments.html