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

策略行为适用
AUTOALLOCATEOracle 自动调整大小(默认 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. 最佳实践

  1. 使用本地管理表空间:性能优于字典管理
  2. 大表用 AUTOALLOCATE:自动调整 extent 大小
  3. 数据仓库用 UNIFORM SIZE:减少碎片
  4. 大表分区:便于管理 HWM
  5. DELETE 后 SHRINK:降低 HWM
  6. TRUNCATE 优于 DELETE:清空表用 TRUNCATE
  7. 历史数据归档:使用分区交换
  8. 定期运行 Segment Advisor:识别优化机会
  9. HWM 监控blocks - used_blocks 比例高时处理
  10. 生产用在线重定义:避免停机

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