数据库基础体系 · 第 106/139 篇。文章以各产品官方稳定版本的公开语义为准;示例会明确引擎、事务与部署边界。

Oracle 存储管理:Tablespace、Segment、Extent、Block 和 ASM

在 Oracle 中,一行数据从逻辑对象到物理存储,通常要经过这样一条链路:

表或索引
  -> Segment
  -> Extent
  -> Oracle Block
  -> Datafile
  -> ASM File
  -> ASM Disk Group
  -> 物理磁盘或云块存储

这条链路描述的是不同层次的对象。TablespaceSegmentExtentBlock 主要属于 Oracle 数据库存储模型;ASM 则是 Oracle 提供的卷管理和文件系统抽象,用来管理数据库文件所在的存储池。ASM 不会替代这些数据库逻辑概念,也不会把表直接“存进 ASM”。


一、先区分逻辑存储和物理存储

Oracle 存储模型可以分成两组概念。

1. 数据库逻辑层

对象 作用
Tablespace 数据库中的逻辑存储容器
Segment 某个表、索引、LOB 或其他对象实际使用的空间
Extent Segment 一次分配的一组连续数据块
Block Oracle 管理数据的最小 I/O 单位

2. 数据库文件和存储层

对象 作用
Datafile Tablespace 在操作系统或 ASM 中对应的数据文件
Tempfile 临时表空间使用的临时文件
ASM Disk Group ASM 管理的磁盘存储池
ASM File ASM 为数据库文件提供的文件抽象
ASM Disk ASM 使用的底层磁盘、分区、LUN 或其他设备

一个 Tablespace 可以包含一个或多个 Datafile;一个 Datafile 属于一个 Tablespace;一个 Segment 可以跨越多个 Datafile,但一个 Extent 不会跨越 Datafile。

因此,下面这些说法并不等价:

表属于某个 Tablespace
表占用了若干 Segment
Segment 占用了若干 Extent
Extent 使用了一组 Block
Block 位于某个 Datafile
Datafile 可能由 ASM 管理

二、Tablespace:数据库的逻辑存储容器

Tablespace 是 Oracle 用来组织数据文件和数据库对象的逻辑结构。表、索引、Undo、临时对象等都需要在某个 Tablespace 中分配空间。

创建普通永久 Tablespace 的一个示例是:

CREATE TABLESPACE app_data
  DATAFILE '/u01/oradata/DB01/app_data01.dbf'
  SIZE 100M
  AUTOEXTEND ON
  NEXT 10M
  MAXSIZE 1G
  EXTENT MANAGEMENT LOCAL
  SEGMENT SPACE MANAGEMENT AUTO;

这个命令包含几个不同层次的配置:

  • app_data 是 Tablespace 名称。
  • DATAFILE 指定实际数据文件。
  • SIZE 100M 指定数据文件初始大小。
  • AUTOEXTEND ON 允许数据文件自动增长。
  • NEXT 10M 指定每次自动扩展的增量。
  • MAXSIZE 1G 限制自动扩展上限。
  • EXTENT MANAGEMENT LOCAL 表示 Extent 的空闲状态由 Tablespace 内部位图管理。
  • SEGMENT SPACE MANAGEMENT AUTO 表示使用 ASSM,即 Automatic Segment Space Management。

生产环境通常优先使用 locally managed tablespace。Dictionary-managed tablespace 属于较早的管理方式,在现代数据库设计中通常不应作为新建对象的默认选择。

1. Tablespace 不等于 Datafile

下面的查询可以查看 Tablespace 和 Datafile 的关系:

SELECT
    tablespace_name,
    file_id,
    file_name,
    bytes,
    autoextensible,
    maxbytes
FROM dba_data_files
ORDER BY tablespace_name, file_id;

可能得到类似结果:

TABLESPACE_NAME  FILE_ID  FILE_NAME                         BYTES   AUTOEXTENSIBLE  MAXBYTES
---------------  -------  -------------------------------- ------  --------------  --------
APP_DATA         7        /u01/oradata/DB01/app_data01.dbf 104857600 YES             1073741824

这里:

  • Tablespace 的大小通常是其 Datafile 大小之和;
  • Datafile 的自动扩展上限不一定等于文件当前大小;
  • Datafile 文件存在,并不代表其中已经有表或索引;
  • Tablespace 空间足够,也不代表某个 Segment 一定能立即分配空间,因为还要受到文件上限、数据文件可用空间、配额和其他约束影响。

可以把 Tablespace 看成数据库的逻辑地址空间,而 Datafile 是这个地址空间的物理承载文件。

2. Smallfile 和 Bigfile Tablespace

Oracle 支持两类主要 Tablespace 文件组织方式:

  • Smallfile tablespace:可以包含多个 Datafile;
  • Bigfile tablespace:通常只有一个很大的 Datafile。

Bigfile tablespace 简化了文件数量管理,但单个文件的容量、备份、恢复和底层存储能力需要单独评估。它不是“自动拥有更多空间”,而是改变了 Tablespace 到 Datafile 的组织方式。

3. 永久、临时和 Undo Tablespace

不同 Tablespace 的空间语义并不完全相同:

  • 永久 Tablespace 保存表、索引等持久对象;
  • 临时 Tablespace 保存排序、哈希连接、临时表等操作产生的临时段;
  • Undo Tablespace 保存 Undo Segment,用于事务回滚、读一致性和闪回相关机制。

临时空间不足时,常见错误是 ORA-01652: unable to extend temp segment。这不一定说明永久表空间不足,而可能是某个排序或连接操作需要更多临时空间。

永久 Tablespace 空间不足时,常见错误是:

ORA-01653: unable to extend table ...
ORA-01654: unable to extend index ...

这些错误说明对应 Segment 需要获得新的 Extent,但 Tablespace 无法满足分配请求。


三、Block:Oracle 管理数据的最小单位

Oracle Block 是 Oracle 数据库执行数据读写时使用的基本单位。一个 Block 通常对应 Datafile 中一段固定大小的连续字节。

数据库的标准 Block 大小由初始化参数 DB_BLOCK_SIZE 决定,常见值是 8 KB。Oracle 也支持在满足条件时配置多个 Block Size,例如使用 2 KB、4 KB、8 KB、16 KB 或 32 KB 的 Tablespace Block Size,但不同 Block Size 需要对应的 Buffer Cache 配置。

可以查看数据库 Block Size:

SELECT name, value
FROM v$parameter
WHERE name IN ('db_block_size', 'db_cache_size');

查看各 Tablespace 的 Block Size:

SELECT
    tablespace_name,
    block_size,
    extent_management,
    segment_space_management
FROM dba_tablespaces
ORDER BY tablespace_name;

1. Block 的容量计算

如果某个 Tablespace 的 Block Size 是 8 KB,一个 1 MB 的 Extent 理论上包含:

Block 数量=Extent 字节数Block 字节数=1×1024×10248×1024=128\text{Block 数量} = \frac{\text{Extent 字节数}}{\text{Block 字节数}} = \frac{1 \times 1024 \times 1024}{8 \times 1024} = 128

因此,1 MB Extent 在 8 KB Block 的 Tablespace 中通常对应 128 个 Block。

这是空间换算关系,不代表每个 Block 都能存放:

8192行大小\frac{8192}{行大小}

条记录。因为 Block 还需要容纳 Block Header、行目录、事务槽、空闲空间,以及行迁移、变长列等额外结构。

2. Block 的内部结构

一个普通数据 Block 通常包含:

+----------------------+
| Block Header         |
+----------------------+
| Table Directory      |
+----------------------+
| Row Directory        |
+----------------------+
| Free Space           |
+----------------------+
| Row Data             |
+----------------------+

其中:

  • Block Header 保存 Block 管理信息;
  • Table Directory 用于标识该 Block 中涉及的表;
  • Row Directory 保存行的位置指针;
  • Free Space 用于插入新行、行增长和事务相关结构;
  • Row Data 保存实际行数据。

Block 的剩余空间并不全部可以用于行数据。PCTFREE 控制 Block 预留多少空间用于已有行的后续更新。例如:

CREATE TABLE orders (
    order_id NUMBER PRIMARY KEY,
    note     VARCHAR2(4000)
)
PCTFREE 20;

PCTFREE 20 的含义不是“永远浪费 20% 空间”,而是当 Block 用于插入时,Oracle 会尽量保留一部分空间,避免后续更新行时没有空间。实际行为还会受到行大小、更新方式和段空间管理机制影响。

3. Block 与并发

多个会话可能同时访问同一个 Block。Oracle 在 Block 中维护事务相关信息,例如 ITL(Interested Transaction List),以记录哪些事务正在修改该 Block 中的行。

当并发事务很多,而 Block 中可用的 ITL 槽不足时,可能出现与事务槽扩展或并发等待相关的问题。对于 ASSM Tablespace,可以通过 INITRANS 等属性影响初始事务槽配置,但不能把 INITRANS 简单理解成“允许的最大并发事务数”。

Oracle 的行级锁最终也需要在 Block 的数据结构中体现。锁的是行,而不是通常意义上的整张表或整个数据文件;但多个热点行集中在少数 Block 上时,仍可能形成 Block 级别的并发争用。

4. HWM 与 Block

Segment 会记录高水位线(High Water Mark,HWM)。HWM 表示该 Segment 曾经扩展到的边界。

例如:

  1. 表初始分配 100 个 Block;
  2. 插入数据,使用其中 20 个 Block;
  3. 删除全部数据;
  4. Segment 仍可能保留 100 个 Block,HWM 也不会因为普通 DELETE 自动回退。

因此,下面两种“空间”不同:

  • Segment 已经分配给表的空间;
  • Segment 内当前可以再次使用的空闲空间。

执行普通全表扫描时,Oracle 通常需要检查 HWM 以下的 Block,即使其中很多 Block 已经没有有效行。DELETE 释放的空间可以被该 Segment 后续使用,但通常不会自动返还给 Tablespace。

可以通过 TRUNCATE、Segment Shrink 或重组等方式改变空间状态,但这些操作的锁、ROWID、索引、UNDO 和业务影响不同,不能只按“释放空间”理解。


四、Extent:Segment 一次获得的一组 Block

Extent 是 Segment 向 Tablespace 申请空间时一次获得的一组连续 Oracle Block。它是 Segment 和 Block 之间的分配单位。

如果:

  • Block Size = 8 KB;
  • Extent = 1 MB;

那么一个 Extent 包含 128 个 Block。某个 Segment 分配了 10 个这样的 Extent,则其理论分配空间为:

10×1 MB=10 MB10 \times 1\text{ MB}=10\text{ MB}

对应:

10×128=1280 个 Block10 \times 128=1280\text{ 个 Block}

查询 Segment 的 Extent:

SELECT
    owner,
    segment_name,
    segment_type,
    tablespace_name,
    extent_id,
    file_id,
    block_id,
    blocks,
    bytes
FROM dba_extents
WHERE owner = 'APP'
  AND segment_name = 'ORDERS'
ORDER BY extent_id;

字段含义包括:

  • EXTENT_ID:该 Segment 内 Extent 的编号;
  • FILE_ID:Extent 所在 Datafile 的文件编号;
  • BLOCK_ID:Extent 起始 Block;
  • BLOCKS:Extent 包含的 Block 数;
  • BYTES:Extent 大小。

1. Extent 不一定连续覆盖整个 Segment

一个 Segment 的多个 Extent 可以位于:

  • 同一个 Datafile 的不同区域;
  • 同一个 Tablespace 的不同 Datafile;
  • 由于历史增长和空间回收而分散的位置。

但一个 Extent 本身位于单个 Datafile 中,并表示该文件内一段连续的 Oracle Block。

因此,“表的数据在磁盘上连续”通常是不正确的。即使 Extent 在 Datafile 内连续,也不能直接推断底层磁盘上的物理扇区一定连续,特别是在 ASM、RAID、存储虚拟化或云块存储环境中。

2. Extent 的分配策略

Locally managed tablespace 主要有两种常见 Extent 分配策略:

CREATE TABLESPACE uniform_demo
  DATAFILE '/u01/oradata/DB01/uniform_demo01.dbf'
  SIZE 100M
  EXTENT MANAGEMENT LOCAL
  UNIFORM SIZE 1M;

UNIFORM SIZE 1M 表示该 Tablespace 中的 Extent 使用统一大小。

另一种是:

CREATE TABLESPACE auto_demo
  DATAFILE '/u01/oradata/DB01/auto_demo01.dbf'
  SIZE 100M
  EXTENT MANAGEMENT LOCAL
  AUTOALLOCATE;

AUTOALLOCATE 由 Oracle 根据 Segment 的增长阶段选择 Extent 大小。它不保证所有 Extent 大小相同,也不应假设每次分配都严格等于对象定义中的 NEXT 值。

NEXT 等存储参数在现代 locally managed tablespace 和自动分配策略下,不能简单视为“下一次一定分配这么多字节”。实际大小还受到 Tablespace 的分配策略、Segment 类型和版本实现影响。

3. Segment 与 Extent 的实际示例

下面示例假设:

  • 使用 Oracle 数据库;
  • 当前用户具有创建 Tablespace、用户和对象的权限;
  • 数据文件路径 /u01/oradata/DB01/ 已存在且 Oracle 进程有权限访问;
  • 这是文件系统部署,不是 ASM 部署。
CREATE TABLESPACE lab_data
  DATAFILE '/u01/oradata/DB01/lab_data01.dbf'
  SIZE 20M
  AUTOEXTEND ON
  NEXT 5M
  MAXSIZE 100M
  EXTENT MANAGEMENT LOCAL
  AUTOALLOCATE
  SEGMENT SPACE MANAGEMENT AUTO;

CREATE USER lab IDENTIFIED BY "StrongPassword_1"
  DEFAULT TABLESPACE lab_data
  QUOTA 50M ON lab_data;

GRANT CREATE SESSION, CREATE TABLE TO lab;

CONN lab/"StrongPassword_1"

CREATE TABLE t_demo (
    id   NUMBER PRIMARY KEY,
    text VARCHAR2(100)
);

INSERT INTO t_demo
SELECT level, RPAD('x', 100, 'x')
FROM dual
CONNECT BY level <= 10000;

COMMIT;

随后以具有数据字典查询权限的用户检查:

SELECT
    segment_name,
    segment_type,
    tablespace_name,
    bytes,
    blocks,
    extents
FROM dba_segments
WHERE owner = 'LAB'
  AND segment_name IN ('T_DEMO', 'SYS_C0012345');

实际约束名可能不同,因此主键索引名称最好通过以下查询确认:

SELECT index_name, table_name
FROM dba_indexes
WHERE owner = 'LAB'
  AND table_name = 'T_DEMO';

再查看表的 Extent:

SELECT
    segment_name,
    extent_id,
    file_id,
    block_id,
    blocks,
    bytes
FROM dba_extents
WHERE owner = 'LAB'
  AND segment_name = 'T_DEMO'
ORDER BY extent_id;

这个过程说明:

  1. 创建表时,Oracle 创建的是表对象定义;
  2. 在启用 deferred segment creation 的环境中,空表可能暂时没有分配表 Segment;
  3. 插入第一批数据或显式分配空间后,表 Segment 才会产生;
  4. 表增长时,Oracle 从 LAB_DATA 的空闲空间中分配 Extent;
  5. Extent 再由多个 Block 组成;
  6. 主键还会产生一个独立的索引 Segment。

“一个表对应一个 Segment”也不是绝对规律:

  • 分区表通常每个分区有独立 Segment;
  • 分区索引可能每个分区有独立 Segment;
  • LOB 列通常会产生独立的 LOB Segment 和索引 Segment;
  • 临时对象和 Undo 对象有自己的 Segment 生命周期;
  • 空表可能只有对象元数据而尚未分配 Segment。

五、Segment:对象实际使用空间的边界

Segment 是 Oracle 为某类数据库对象分配的一组 Extent。它描述的是“某个对象已经获得的空间”,而不是对象的全部逻辑定义。

常见 Segment 类型包括:

  • TABLE:普通堆表;
  • INDEX:索引;
  • TABLE PARTITION:表分区;
  • INDEX PARTITION:索引分区;
  • LOBSEGMENT:LOB 数据;
  • LOBINDEX:LOB 索引;
  • UNDO:Undo 段;
  • TEMPORARY:临时段。

查询用户 Segment:

SELECT
    owner,
    segment_name,
    partition_name,
    segment_type,
    tablespace_name,
    bytes,
    blocks,
    extents
FROM dba_segments
WHERE owner = 'APP'
ORDER BY bytes DESC;

需要注意:

DBA_SEGMENTS.BYTES

表示 Segment 已分配的空间,不等于有效行数据的字节数,也不等于查询结果中所有列的逻辑长度之和。

例如,一个表可能有:

  • 大量删除后留下的 Segment 空间;
  • PCTFREE 预留空间;
  • 行迁移产生的额外空间;
  • LOB 数据存储在独立 Segment;
  • 索引 Segment 大于表中的某些有效数据量。

1. Segment 空间和 Tablespace 空闲空间

Tablespace 空闲空间是“尚未分配给 Segment 的空间”。

Segment 内部空闲空间是“已经属于该 Segment,但目前没有存放有效行或索引条目的空间”。

二者不能混淆:

Tablespace Free Space
    = 可以分配给新的或增长中的 Segment 的空间

Segment Free Space
    = 已归某个 Segment 所有、可由该 Segment 重用的空间

执行 DELETE 通常只增加 Segment 内部可重用空间,不会直接增加 Tablespace 空闲空间。

检查 Tablespace 文件和空闲空间:

SELECT
    tablespace_name,
    SUM(bytes) AS free_bytes
FROM dba_free_space
GROUP BY tablespace_name
ORDER BY tablespace_name;

在 ASSM Tablespace 中,可以进一步使用 DBMS_SPACE 分析 Segment 内部空间,但该接口需要适当权限,并且不同 Segment 类型支持的分析方式存在差异。不能仅通过 DBA_SEGMENTS.BYTES 判断表内有多少空间真正可插入。


六、ASM:为数据库文件提供存储池和文件管理

ASM(Automatic Storage Management)是 Oracle 提供的存储管理组件。它位于数据库文件和底层存储设备之间,主要负责:

  • 将多个磁盘组织成 Disk Group;
  • 为数据库文件提供文件抽象;
  • 对数据进行条带化;
  • 在配置了镜像冗余时提供 ASM 层面的镜像;
  • 通过重新平衡在磁盘加入、移除或容量变化后迁移数据;
  • 管理 ASM 文件元数据和空间分配。

ASM 不是数据库 Buffer Cache,也不是 SQL 层面的表空间管理器。

1. ASM 的层次

数据库文件
  -> ASM File
  -> ASM Disk Group
  -> ASM Disk
  -> 底层存储设备

例如,一个数据文件可能被写成:

CREATE TABLESPACE asm_data
  DATAFILE '+DATA'
  SIZE 1G
  AUTOEXTEND ON
  NEXT 100M
  MAXSIZE 10G
  EXTENT MANAGEMENT LOCAL
  SEGMENT SPACE MANAGEMENT AUTO;

这里的 +DATA 是 ASM Disk Group 名称。Oracle 会在该 Disk Group 中创建和管理实际 ASM 文件。用户不需要提供传统操作系统路径。

也可以使用别名:

+DATA/DB01/DATAFILE/ASM_DATA.123.987654321

这类名称表达的是 ASM 文件位置和标识,不是普通文件系统中的目录路径。

2. ASM Disk Group 和冗余

ASM Disk Group 把多个 ASM Disk 组成一个存储池。Disk Group 创建时可以指定冗余策略,例如:

  • External redundancy:由外部存储系统提供镜像;
  • Normal redundancy:由 ASM 提供相应镜像;
  • High redundancy:提供更高等级的 ASM 镜像保护。

选择时必须明确“谁负责冗余”:

ASM 冗余 + 存储阵列冗余

不一定比单独一种冗余更合理,可能增加容量消耗和管理复杂度。反过来,External redundancy 也不是“没有保护”,它表示保护责任交给底层存储系统。

可以查看 ASM Disk Group:

SELECT
    name,
    state,
    type,
    total_mb,
    free_mb,
    required_mirror_free_mb,
    usable_file_mb
FROM v$asm_diskgroup;

几个字段不能混为一谈:

  • TOTAL_MB:Disk Group 总容量;
  • FREE_MB:未分配空间;
  • REQUIRED_MIRROR_FREE_MB:为维持镜像和故障恢复所需保留的空间;
  • USABLE_FILE_MB:考虑冗余和镜像要求后,数据库文件实际可以安全使用的估算空间。

因此,FREE_MB 并不总是等于“还能创建多少可用数据文件空间”。

3. ASM Allocation Unit 与 Oracle Extent

ASM 也有自己的分配单位,称为 Allocation Unit(AU)。Oracle 数据库还有自己的 Extent。二者属于不同层次:

Oracle Segment
  -> Oracle Extent
  -> Oracle Block

Oracle Datafile
  -> ASM File
  -> ASM Extent / Allocation Unit
  -> ASM Disk

不要因为两者都使用“extent”这个词,就认为它们是同一个对象。

  • Oracle Extent 面向数据库对象空间;
  • ASM 文件分配面向存储池空间;
  • Oracle Block 是数据库访问单位;
  • ASM AU 是 ASM 管理空间和条带化的单位。

Oracle 通过 Datafile 把数据库 Block 的逻辑地址映射到 ASM 文件。一个数据库进程只需要访问某个 Datafile 的某个 Block,不需要直接知道该 Block 最终落在哪块 ASM Disk 上。

4. ASM 条带化与数据库 I/O

ASM 可以把文件数据分散到多个磁盘上,以获得并行 I/O。常见概念包括:

  • coarse striping:较大的条带单位;
  • fine striping:较小的条带单位,适用于对低延迟和并发 I/O 有特殊要求的文件类型。

条带化的目标是改善 I/O 分布,不意味着每个 SQL 查询都会自动获得线性性能提升。实际效果还取决于:

  • SQL 是否产生足够的并发 I/O;
  • Buffer Cache 命中率;
  • 存储阵列或云存储的吞吐限制;
  • 数据文件布局;
  • RAC 实例之间的访问模式;
  • I/O 调度和底层设备队列。

ASM 不能修复错误的索引设计、全表扫描、过小的内存配置或存储设备本身的性能瓶颈。

5. ASM Rebalance

当 ASM Disk Group 中加入或移除磁盘时,ASM 可以执行 Rebalance,把文件数据重新分布到新的磁盘集合中。

典型状态变化是:

磁盘加入
  -> ASM 更新 Disk Group 元数据
  -> 产生重新平衡操作
  -> 数据块逐步迁移
  -> 新旧磁盘分布趋于均衡

可以查看操作:

SELECT
    group_number,
    operation,
    state,
    power,
    sofar,
    est_work,
    est_minutes
FROM v$asm_operation;

Rebalance 不是瞬时操作。提高 POWER 通常会增加后台迁移工作的资源使用,但具体影响取决于版本、存储设备和当前 I/O 负载。生产环境需要结合业务负载观察,而不能只根据一个固定数值判断安全与否。


七、从 SQL 到磁盘:一次数据访问经过什么路径

以查询某一行数据为例,逻辑过程可以简化为:

SQL 解析和执行
  -> 根据表或索引定位 RowID
  -> RowID 指向 Datafile 和 Block
  -> 检查 Buffer Cache
  -> 未命中时发起物理读
  -> 访问 ASM 文件
  -> ASM 将文件偏移映射到 AU 和底层磁盘
  -> 数据返回 Buffer Cache
  -> SQL 引擎读取行

RowID 通常包含对象、数据文件相对编号和 Block 等定位信息。可以用 DBMS_ROWID 查看普通堆表 RowID 的部分信息:

SELECT
    rowid,
    DBMS_ROWID.ROWID_RELATIVE_FNO(rowid) AS relative_file_no,
    DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid) AS block_no
FROM app.orders
WHERE order_id = 1001;

这个示例需要满足:

  • 查询的是支持这种 RowID 解释方式的普通堆表;
  • 当前用户有执行 DBMS_ROWID 的权限;
  • 分区表、索引组织表、迁移行等场景需要额外考虑。

RowID 是行的物理定位信息,不应当被当作永久业务主键。表移动、分区维护、Segment 重组等操作可能改变 RowID。


八、Block、Extent、Segment 与 ASM 的边界

下面这个例子可以说明各层的职责:

表 ORDERS
  -> ORDERS 表 Segment
      -> Extent 0
          -> Block 1000 ~ 1127
      -> Extent 1
          -> Block 5300 ~ 5427
  -> Datafile 7
      -> ASM File +DATA/...
          -> ASM AU 分布在多个 ASM Disk

这里:

  • ORDERS 是逻辑表;
  • 表 Segment 负责保存表数据;
  • Extent 0 和 Extent 1 是 Segment 的两次空间分配;
  • 每个 Extent 包含一组 Oracle Block;
  • 两个 Extent 可以在 Datafile 中相距很远;
  • Datafile 可能是 ASM File;
  • ASM 决定 ASM 文件内容如何映射到 Disk Group;
  • SQL 层不需要直接操作 ASM Disk。

因此,优化或诊断时必须先确定问题位于哪一层:

现象 可能相关层次
表空间满 Tablespace、Datafile、ASM Disk Group
表增长失败 Segment、Extent、配额、Datafile
全表扫描慢 Block、HWM、Buffer Cache、I/O
热点块争用 Block、ITL、并发访问
ASM 空间不足 Disk Group 冗余、AU、Rebalance
数据文件丢失 Datafile、ASM、RMAN、Data Guard
RAC 跨实例访问代价高 Buffer Cache、Cache Fusion、ASM 共享存储

九、常见误解与失败表现

1. “删除数据后 Tablespace 空间就增加了”

通常不成立。

DELETE FROM app.orders;
COMMIT;

这通常只让表 Segment 内的 Block 变得可重用,不会自动降低 DBA_SEGMENTS.BYTES,也不会直接增加 DBA_FREE_SPACE

如果业务确实需要把空间还给 Tablespace,需要根据对象类型和业务窗口评估 TRUNCATESHRINK SPACE、移动 Segment 或重建对象等方案。

2. “AUTOEXTEND ON 说明空间不会耗尽”

不成立。自动扩展仍然受以下因素限制:

  • MAXSIZE
  • 文件系统或 ASM Disk Group 容量;
  • ASM 冗余后的可用容量;
  • 数据库或用户配额;
  • 存储设备故障;
  • 数据文件最大尺寸;
  • 实例和数据库配置。

因此要同时检查:

SELECT
    tablespace_name,
    file_name,
    bytes,
    maxbytes,
    autoextensible
FROM dba_data_files;

SELECT
    tablespace_name,
    SUM(bytes) AS free_bytes
FROM dba_free_space
GROUP BY tablespace_name;

ASM 部署还要检查:

SELECT
    name,
    state,
    type,
    total_mb,
    free_mb,
    usable_file_mb
FROM v$asm_diskgroup;

3. “Extent 是物理磁盘上的连续区域”

不成立。

Extent 只是在 Oracle Datafile 层面由一组连续 Block 组成。Datafile 可能位于 ASM、RAID、LVM、存储阵列或虚拟化存储上,数据库无法也不应该把 Extent 直接等同于底层磁盘连续区间。

4. “ASM 就是 RAID”

不完全正确。

ASM 提供条带化、镜像和存储池管理,但它的冗余语义、故障域和恢复行为与传统 RAID 并不完全相同。使用 External redundancy 时,ASM 假设底层存储负责数据保护;使用 ASM redundancy 时,镜像由 ASM 管理。

5. “Tablespace 有空闲空间,任何表都能立即扩展”

不一定。

还需要考虑:

  • 空闲空间是否位于合适的 Datafile;
  • Datafile 是否达到上限;
  • 用户是否有 Tablespace quota;
  • Segment 的 Extent 分配策略;
  • 临时表空间或 Undo 表空间的特殊语义;
  • ASM Disk Group 是否有满足冗余要求的可用空间。

十、故障路径和恢复边界

Tablespace、Datafile 和 ASM 的故障恢复责任不同。

1. Datafile 损坏或丢失

数据库可能报告数据文件不可访问、块损坏或无法扩展。恢复通常涉及:

  • RMAN 从备份恢复 Datafile;
  • 使用归档日志和在线重做日志进行介质恢复;
  • 如果有 Data Guard,可能从备用库获取对应保护;
  • 如果是 ASM 故障,还要判断是单盘、磁盘组、路径还是底层存储故障。

ASM 镜像主要解决部分存储故障可用性问题,不等于数据库备份。误删表、错误更新、逻辑损坏通常不能依靠 ASM 镜像恢复到历史业务状态,仍需要 RMAN、闪回或其他逻辑恢复手段。

2. RAC 与 ASM

RAC 中多个数据库实例可以共享同一个 ASM Disk Group。ASM 负责共享存储和文件管理;RAC 实例之间的数据块缓存一致性由 Cache Fusion 等数据库集群机制负责。

因此:

ASM 解决“多个实例如何看到数据库文件”
RAC 解决“多个实例如何共同访问并协调数据库”

ASM 本身不能替代 RAC 的锁管理和缓存一致性机制。

3. Data Guard 与 ASM

Data Guard 负责主库和备用库之间的日志传输、应用和角色切换。主库和备用库都可以使用 ASM,但两者的 ASM Disk Group 通常属于各自主机或存储环境。

因此:

ASM:单个数据库环境中的文件和磁盘管理
Data Guard:数据库副本之间的灾难恢复和高可用
RMAN:备份、恢复和介质恢复

它们可以组合使用,但职责不同。


十一、诊断时应按层次逐步定位

遇到“空间不足”或“对象增长失败”时,可以按以下顺序检查,而不是直接扩容。

第一步:确认 Tablespace 类型和 Block Size

SELECT
    tablespace_name,
    status,
    contents,
    extent_management,
    allocation_type,
    segment_space_management,
    block_size
FROM dba_tablespaces
WHERE tablespace_name = 'APP_DATA';

第二步:确认 Datafile 当前大小和上限

SELECT
    file_id,
    file_name,
    bytes / 1024 / 1024 AS current_mb,
    maxbytes / 1024 / 1024 AS max_mb,
    autoextensible
FROM dba_data_files
WHERE tablespace_name = 'APP_DATA';

第三步:确认空闲空间和最大空闲区

SELECT
    tablespace_name,
    SUM(bytes) / 1024 / 1024 AS free_mb,
    MAX(bytes) / 1024 / 1024 AS largest_free_extent_mb
FROM dba_free_space
WHERE tablespace_name = 'APP_DATA'
GROUP BY tablespace_name;

Locally managed tablespace 下,传统意义上的碎片问题与旧式字典管理不同,但“总空闲空间足够”仍不必然意味着某次具体分配一定成功,因为文件上限、配额和分配边界仍然存在。

第四步:确认哪个 Segment 在增长

SELECT
    owner,
    segment_name,
    segment_type,
    bytes / 1024 / 1024 AS allocated_mb,
    extents
FROM dba_segments
WHERE tablespace_name = 'APP_DATA'
ORDER BY bytes DESC;

第五步:ASM 部署检查 Disk Group

SELECT
    name,
    state,
    type,
    total_mb,
    free_mb,
    usable_file_mb
FROM v$asm_diskgroup
ORDER BY name;

如果发现 ASM 正在 Rebalance,还应查看:

SELECT *
FROM v$asm_operation;

这样可以区分:

数据库对象空间增长问题
Tablespace/Datafile 容量问题
ASM Disk Group 可用空间问题
底层存储或路径故障

十二、一个完整的空间推导例子

假设某个 Tablespace:

  • Block Size 为 8 KB;
  • 一个表 Segment 已分配 64 个 Extent;
  • 每个 Extent 为 4 MB;
  • 其中有效数据约占已分配 Block 的 55%。

则:

1. 已分配空间

64×4 MB=256 MB64 \times 4\text{ MB}=256\text{ MB}

2. 每个 Extent 的 Block 数

4×1024 KB8 KB=512\frac{4 \times 1024\text{ KB}}{8\text{ KB}} =512

3. Segment 的 Block 总数

64×512=3276864 \times 512=32768

4. 估算有效数据占用

256 MB×55%=140.8 MB256\text{ MB}\times 55\%=140.8\text{ MB}

但这个 140.8 MB 只是估算的有效数据比例,不能直接当作 Oracle 的精确“数据大小”。精确分析还需要考虑:

  • Block Header;
  • 行目录;
  • PCTFREE;
  • 行迁移和行链接;
  • 事务槽;
  • 变长列;
  • LOB 外置存储;
  • 索引单独占用的 Segment;
  • 空间回收和重用状态。

这个例子最重要的结论不是某个百分比,而是:

Segment 已分配空间
≠ 有效行数据大小
≠ 表逻辑列长度之和
≠ Tablespace 当前剩余空间

结语

Oracle 存储管理的核心是把不同层次准确对应起来:

Tablespace:逻辑容器
Segment:对象已经获得的空间
Extent:Segment 一次分配的一组 Block
Block:Oracle 访问和管理数据的基本单位
Datafile:Tablespace 的数据库文件承载
ASM:管理数据库文件所在存储池和底层映射

当对象增长、空间耗尽、I/O 变慢或存储发生故障时,只有先确定问题位于哪一层,才能选择正确的处理方式。扩展 Datafile、回收 Segment 空间、增加 ASM 磁盘、调整 Block 或处理 RMAN/Data Guard 故障,解决的是完全不同的问题。


系列导航与关联阅读

官方资料

本文依据数据库官方文档重新梳理;正文、示例与生产检查清单由 WR BLOG 编写。