一、概述
在 Oracle 数据库日常运维中,表空间使用率偏高、数据文件持续增长是比较常见的容量管理问题。
当某个表空间占用达到数百 GB 甚至 TB 级别时,仅查看表空间使用率并不能确定问题来源,需要进一步分析到底是哪些业务表、索引或大字段占用了存储空间。
本文以 Oracle 19c 为例,首先介绍 Oracle 的基本存储结构及 LOB 大对象存储机制,再结合 Toad for Oracle 图形化工具,介绍一套可复用的数据库空间排查方法。
核心排查流程:
表空间容量 → 数据文件 → 大对象排名 → 大表/索引/LOB 字段 → 业务数据分析 → 问题反馈。
二、Oracle 数据库存储基础
Oracle Database(数据库) │ └── Tablespace(表空间) │ ├── ① 逻辑存储结构(数据如何组织) │ │ │ ├── Segment(段) │ │ ├── Table Segment(表段) │ │ ├── Index Segment(索引段) │ │ └── LOB Segment(大对象段) │ │ │ └── 每个 Segment 由多个 Extent 组成 │ │ │ ├── Extent 1(区) │ │ ├── Block 1(数据块) │ │ ├── Block 2(数据块) │ │ └── Block 3(数据块) │ │ │ └── Extent 2(区) │ ├── Block 4(数据块) │ ├── Block 5(数据块) │ └── Block 6(数据块) │ └── ② 物理存储结构(数据存在哪里) │ ├── Datafile 01(数据文件) │ ├── Extent A │ │ ├── Block │ │ └── Block │ └── Extent B │ ├── Block │ └── Block │ ├── Datafile 02(数据文件) │ └── Extent C │ ├── Block │ └── Block │ └── Datafile 03(数据文件) └── Extent D ├── Block └── Block2.1 表空间、数据文件与段的关系
一句话:Block负责存数据,Extent负责分配空间,Segment负责组织对象,Datafile负责物理承载。
Oracle 数据库采用逻辑存储与物理存储相结合的方式管理数据。
| 存储概念 | 英文名称 | 作用 |
|---|---|---|
| 表空间 | Tablespace | 逻辑存储容器,用于组织数据库对象 |
| 数据文件 | Datafile | 表空间对应的物理存储文件 |
| 段 | Segment | 为表、索引、LOB 等对象分配的存储空间 |
| 区 | Extent | 段获得的一组连续 Oracle 数据块 |
| 数据块 | Data Block | Oracle 数据库 I/O 和存储的基本逻辑单位 |
Tablespace管理空间,Datafile承载数据,Segment组织对象,Extent分配空间,Block实际存储数据。
其基本关系如下:
一个表空间可以包含多个数据文件。
一个表空间可以存储多个表、索引和 LOB 段。
一个段由一个或多个 Extent 组成。
一个 Extent 由多个 Oracle 数据块组成。
例如:
TS_APP_DATA 表空间
| 数据库对象 | 类型 | 空间大小 |
|---|---|---|
| T_BUSINESS_LOG | TABLE | 106 GB |
| T_MESSAGE_INFO | TABLE | 58 GB |
| SYS_LOB...C00002$$ | LOBSEGMENT | 64.5 GB |
| IDX_BUSINESS_TIME | INDEX | 12 GB |
上述对象可以位于同一个表空间,通过数据文件占用底层存储空间。
因此,数据文件占用的是底层存储容量,而 TABLE、INDEX、LOBSEGMENT 等段是具体的空间分配对象。
2.2 TABLE、INDEX、LOBSEGMENT 的区别
Oracle 中,一张业务表可能关联多个不同的存储段。
| 段类型 | 主要存储内容 |
|---|---|
| TABLE | 表中普通字段数据及行内存储的内容 |
| INDEX | 普通业务索引 |
| LOBSEGMENT | 行外存储的 CLOB、BLOB 等大对象内容 |
| LOBINDEX | Oracle 内部管理 LOB 使用的索引结构 |
| TABLE PARTITION | 分区表某个分区的数据 |
| INDEX PARTITION | 分区索引的数据 |
注意:一张业务表的总空间占用,不一定等于 TABLE 段大小。
例如,某业务表:
TABLE 段:10 GB
LOBSEGMENT:500 GB
INDEX 段:5 GB
那么该业务表及关联对象合计已分配约 515 GB,而不是只有 10 GB。
这里的统计需要确保各对象没有重复计算,并明确统计的是当前表空间还是整个数据库。
三、LOB 大对象基础知识
3.1 LOB 是什么?
LOB 是Large Object(大对象)的缩写。
它是 Oracle 提供的一组大对象数据类型,主要用于存储大量文本、二进制文件及其他非结构化数据。
例如:
普通VARCHAR2字段适合存储用户名、状态、编号等较短文本。
而接口返回的大型 JSON、XML 文档,或者图片、PDF、附件等内容,则可以使用 LOB 数据类型。
3.2 Oracle 有哪些 LOB 数据类型?
Oracle 主要提供四种 LOB 类型:
| 类型 | 英文全称 | 存储内容 | 常见用途 |
|---|---|---|---|
| CLOB | Character Large Object | 大容量字符数据 | JSON、XML、文本日志、文章 |
| BLOB | Binary Large Object | 二进制数据 | 图片、PDF、Word、音视频、附件 |
| NCLOB | National Character Large Object | 国家字符集大文本 | 使用国家字符集存储的长文本 |
| BFILE | Binary File | 数据库外部二进制文件的引用 | 引用数据库服务器文件系统中的文件 |
其中:
CLOB、BLOB、NCLOB的数据可以由 Oracle 数据库内部管理,属于内部 LOB。
BFILE则比较特殊:实际文件存储在数据库外部的服务器文件系统中,数据库保存文件定位信息,通过 Oracle 提供只读访问。
因此,不能把 BFILE 理解为普通的数据库内部 LOBSEGMENT。
日常空间排查最常见的通常是 CLOB 和 BLOB。
3.3 为什么 LOB 与普通字段的存储方式不同?
Oracle 普通字段的数据通常存放在 TABLE 数据段中。
但是,对于较大的 LOB 内容,Oracle 可以采用独立的 LOBSEGMENT 进行存储。
例如,某张业务表:
T_INTERFACE_PARAM
| 字段 | 数据类型 | 含义 |
|---|---|---|
| PARAM_ID | VARCHAR2 | 主键 |
| INTERFACE_ID | VARCHAR2 | 接口编号 |
| INPUT_CONTENT | CLOB | 接口请求内容 |
| OUTPUT_CONTENT | CLOB | 接口返回内容 |
| CREATE_TIME | TIMESTAMP | 创建时间 |
这些字段属于同一张表,但 Oracle 可能采用不同的物理存储结构。
普通表段(TABLE)
存储主键、接口编号、创建时间等普通字段,以及必要的 LOB 定位信息。
LOBSEGMENT
存储较大的 INPUT_CONTENT、OUTPUT_CONTENT 等 CLOB 内容。
因此,一张表即使普通 TABLE 段只有 10 GB,其关联的 LOBSEGMENT 也可能达到几百 GB。
3.4 LOB 一定是独立存储的吗?
不一定。
Oracle LOB 支持两种主要存储方式:
| 存储方式 | 英文名称 | 说明 |
|---|---|---|
| 行内存储 | In-Row | 较小的 LOB 内容直接存放在表行中 |
| 行外存储 | Out-of-Row | 较大的 LOB 内容存放在独立 LOBSEGMENT 中 |
启用行内存储时,较小的 LOB 内容通常可以直接保存在表行中,常见界限约为 4 KB,但具体取决于实际存储配置和行空间条件。
大于该范围的 LOB 内容通常使用行外存储。
重要:LOBSEGMENT 独立存储,并不代表一定位于另一块磁盘。
TABLE 和 LOBSEGMENT 可以位于同一个表空间,也可以配置到不同表空间。
3.5 BasicFiles 与 SecureFiles 是什么?
这是 Oracle LOB 的两种存储实现方式,与 CLOB、BLOB 等数据类型不是同一个概念。
| 存储类型 | 说明 |
|---|---|
| BasicFiles LOB | 较早期的 LOB 存储实现 |
| SecureFiles LOB | Oracle 较新的 LOB 存储实现,提供更多高级管理能力 |
Oracle 11g 引入 SecureFiles,Oracle 12c 起将其作为优先采用的 LOB 存储机制。
SecureFiles 支持压缩、去重和加密等高级能力,但具体功能使用可能涉及相应数据库选件授权,并不是所有环境都可以直接启用。
作为 DBA,需要了解:
不同 LOB 存储方式,空间管理机制可能不同。
删除或更新业务数据后,LOB 已分配空间不一定立即减少。
LOB 空间回收不能简单照搬普通表的收缩方式。
实施空间优化前,应先确认 LOB 类型、存储参数及实际使用情况。
四、利用 Toad 图形化排查表空间
4.1 查看表空间使用率
打开 Toad for Oracle,连接目标数据库。
进入:
Database → Administer → Tablespaces
选择Space标签。
重点关注:
| 指标 | 含义 |
|---|---|
| Tablespace | 表空间名称 |
| Usage | 空间使用率 |
| Size | 当前分配的表空间文件容量 |
| Used | 已使用或已分配空间 |
| Free | 剩余可分配空间 |
| Max | 数据文件允许增长的最大容量 |
| Status | 表空间状态 |
首先找出使用率较高、剩余容量较少或增长较快的表空间。
对于启用 Autoextend 的数据文件,还需要注意:允许扩展到 Max,并不意味着底层文件系统或 ASM 磁盘组一定有足够空间。
4.2 查看表空间对应的数据文件
切换到Files标签。
选择目标表空间,查看:
数据文件名称及路径
当前文件大小
自动扩展配置
最大允许扩展容量
通过 Files 页面,可以明确该表空间当前分配了多少底层存储空间。
需要注意:
即使业务数据被删除,Oracle 数据文件通常也不会自动缩小。
因此,数据文件大小不等于当前实际有效业务数据量。
4.3 查找表空间内占用最大的对象
切换到:
Tablespaces → Objects
选择目标表空间。
点击Size列标题,按照占用大小降序排列。
重点查看以下三类对象:
TABLE:查找大表。
INDEX:查找大索引。
LOBSEGMENT:查找 CLOB、BLOB 等大字段。
例如,查询到:
| Object Name | Object Type | Size |
|---|---|---|
| T_BUSINESS_LOG | TABLE | 106 GB |
| SYS_LOB...C00002$$ | LOBSEGMENT | 64.5 GB |
| T_MESSAGE_INFO | TABLE | 58 GB |
| T_SYSTEM_LOG | TABLE | 48 GB |
| IDX_SYSTEM_LOG_TIME | INDEX | 12.6 GB |
此时,就能快速确认表空间内主要的空间占用对象。
但这一步只是找到物理段,还需要进一步确认对象对应的业务用途。
4.4 定位大表
在 Objects 页面中,找到Object Type = TABLE的对象。
操作步骤:
单击选中目标 TABLE。
按键盘F4。
打开 Describe Objects 窗口。
进入 Columns 查看字段。
进入 Stats/Size 查看表段大小及统计信息。
必要时进入 Data 查看少量业务记录。
重点查看:
表占用大小
统计记录数 Num Rows
统计信息时间 Last Analyzed
是否包含 CLOB、BLOB 字段
数据是否属于日志或历史业务记录
其中,Num Rows 通常来自 Oracle 统计信息,不一定是实时准确记录数。
4.5 定位大索引
在 Objects 页面中找到:
Object Type = INDEX
按 Size 降序排列,查看大索引。
选中索引后按 F4,查看索引定义及关联业务表。
重点确认:
索引所属业务表
索引字段
索引大小
是否存在多个占用较大的索引
注意,不能仅因为索引占用几十 GB,就认为索引不合理。
索引是否冗余、是否可以优化,需要结合实际 SQL、执行计划和业务使用情况分析。
4.6 定位 LOB 大字段
在 Objects 页面中找到:
Object Type = LOBSEGMENT
LOB 对象名称通常类似:
SYS_LOB...C00004$$
这样的系统生成名称无法直接说明业务用途。
具体操作:
选中 LOBSEGMENT。
按F4。
Toad 打开关联的 Describe Objects 页面。
查看 Columns 标签中定位的字段。
记录字段名称、数据类型及所属业务表。
在部分 Toad 版本中,F4 可以自动定位到对应的 LOB 字段。
如果没有自动定位,或者不能确认关联关系,应查询 Oracle 的DBA_LOBS数据字典进行验证。
需要注意:
LOBSEGMENT:存储 LOB 数据。LOBINDEX:Oracle 内部用于管理 LOB 的索引结构。两者有关联,但不能混为同一个对象。
4.7 查看业务表及关联 LOB 的空间
通过 F4 打开业务表:
Describe Objects → Stats/Size
这里通常包含以下选项:
| 选项 | 作用 |
|---|---|
| Show Stats | 显示表统计信息 |
| Show Size/Extents | 显示表段大小及 Extent 信息 |
| Include Lobs | 尝试将关联 LOB 空间计入大小显示 |
例如:
Objects 页面显示:
TABLE:9.35 GB
LOBSEGMENT:992 GB
但进入 Stats/Size 后,只显示 9.35 GB。
这是因为 Toad 当前显示的主要是普通 TABLE 段大小,没有包含独立的 LOB 数据段。
此时可以勾选Include Lobs,进一步查看包含 LOB 的空间统计。
具体汇总范围以 Toad 版本和显示结果为准;普通索引通常还需要单独统计。
五、实际案例:某业务表 LOB 占用接近 1 TB
以下采用脱敏后的对象名称,保留具有代表性的空间数据。
5.1 问题现象
某 Oracle 业务表空间占用较高。
通过 Toad 的 Objects 页面发现:
| 对象名称(脱敏) | 对象类型 | 已分配空间 |
|---|---|---|
| SYS_LOB...C00004$$ | LOBSEGMENT | 992 GB |
| T_INTERFACE_PARAM | TABLE | 9.35 GB |
| SYS_LOB...C00003$$ | LOBSEGMENT | 2.2 GB |
| T_INTERFACE_INFO | TABLE | 1.25 GB |
可以发现,最大的对象不是普通 TABLE,而是接近 1 TB 的 LOBSEGMENT。
5.2 定位具体业务字段
在 Toad 中选中 992 GB 的 LOBSEGMENT,按 F4。
随后结合DBA_LOBS核验,确认:
| 项目 | 结果 |
|---|---|
| 业务用户 | APP_USER |
| 业务表 | T_INTERFACE_PARAM |
| 字段 | OUTPUT_CONTENT |
| 数据类型 | CLOB |
| LOB 段已分配空间 | 992 GB |
这说明:
T_INTERFACE_PARAM 表中的 OUTPUT_CONTENT 字段,关联的 LOB 数据段已分配约 992 GB。
注意:另一个 2.2 GB 的 LOB 对象还需要核实其字段归属,不能仅凭系统对象名称推断。
5.3 为什么普通表只有 9.35 GB?
因为 Oracle 将较大的 CLOB 内容存储在独立的 LOBSEGMENT 中。
普通表段主要保存普通字段、部分行内数据和必要的 LOB 定位信息。
因此:
TABLE 9.35 GB + OUTPUT_CONTENT 的 LOBSEGMENT 992 GB
这两部分都属于相关业务表的存储占用,但在 Oracle 中是不同的物理段。
5.4 是否说明 CLOB 有 992 GB 有效数据?
不能直接这么判断。
DBA_SEGMENTS及 Toad Objects 显示的是已分配段空间。
其中可能包括:
当前有效的 LOB 数据
数据修改产生的版本保留空间
已删除数据释放后可在段内复用的空间
段管理及存储开销
所以,已分配 992 GB,不代表当前有效业务内容就是 992 GB,更不代表其中一定有可直接回收的空间。
后续应由 DBA 结合 LOB 存储方式、空间使用情况及业务数据特征进一步核实。
5.5 后续应如何排查?
下一步重点确认:
OUTPUT_CONTENT 实际存储的是 JSON、XML、接口返回报文,还是其他业务数据。
业务记录的时间分布及增长趋势。
是否存在长期保存的历史数据。
是否存在大量反复更新、替换的大对象内容。
是否存在不合理的历史数据保留或重复存储情况。
最终将空间占用情况和业务数据特征反馈开发人员,由开发人员判断保留、归档及业务逻辑优化方案。
六、常见问题与注意事项
6.1 表占用空间大,是否代表记录数一定很多?
不一定。
表空间占用与记录数、单行长度、LOB 存储、索引数量、历史修改情况等都有关系。
一张几十万条记录的表,如果存储大量大字段,可能比一张数千万条普通数据的表占用更多空间。
6.2 删除数据后,为什么空间没有减少?
这是因为 Oracle 通常不会在数据删除后自动缩小已经分配的段或数据文件。
对于 LOB,内部空间的复用和回收还受到 BasicFiles/SecureFiles、保留策略及存储配置影响。
因此,不能简单认为数据删除后,磁盘空间就会立即释放。
6.3 TABLE、LOBSEGMENT 可以位于不同表空间吗?
可以。
一张业务表可能位于 TS_APP_DATA,而它的 LOB 段位于 TS_APP_LOB,普通索引还可能位于 TS_APP_IDX。
因此,在统计某张业务表的完整空间占用时,需要关注不同表空间中的关联对象。
6.4 为什么不能只按 TABLE 类型排序?
因为 Oracle 将表数据、普通索引、大对象数据等分别管理。
如果只查看 TABLE,就可能遗漏占用数百 GB 的 LOBSEGMENT。
正确的排查方式是对 TABLE、INDEX、LOBSEGMENT 等对象进行综合分析。
6.5 图形界面显示大小,就是磁盘真实占用吗?
需要区分三个指标:
| 指标 | 含义 |
|---|---|
| 数据文件当前大小 | 已分配给 Oracle 数据文件的容量 |
| Segment 已分配空间 | 表、索引或 LOB 已获得的空间 |
| 实际有效数据量 | 当前业务数据真实占用情况 |
三者并不完全相等。
即使数据库段内存在可复用空间,也不意味着底层磁盘已经释放了相应容量。
七、生产环境排查原则
日常空间排查应优先采用 Toad 图形化查看和 Oracle 数据字典只读查询。
不建议在未完成评估的情况下直接执行:
大表全量查询或大量 LOB 内容读取
数据删除与历史数据清理
表或 LOB 段收缩
索引重建
数据文件缩小
尤其对于核心业务数据库,应先确认对象归属、空间增长原因及业务影响。
DBA 负责定位空间占用、评估数据库风险;历史业务数据清理、归档及程序优化方案由开发人员评估,按变更流程实施。
八、日常操作速查表
以后遇到 Oracle 表空间容量问题,可以直接按下面的流程排查。
| 步骤 | Toad 操作位置 | 目的 |
|---|---|---|
| 1 | Tablespaces → Space | 确认表空间使用率 |
| 2 | Tablespaces → Files | 确认数据文件大小及路径 |
| 3 | Tablespaces → Objects | 按 Size 排序,找到大对象 |
| 4 | TABLE → F4 | 分析大表 |
| 5 | INDEX → F4 | 分析大索引 |
| 6 | LOBSEGMENT → F4 | 定位大字段 |
| 7 | Stats/Size → Include Lobs | 查看关联 LOB 的空间 |
| 8 | Data | 查看少量业务数据 |
| 9 | 汇总排查结果 | 反馈开发及相关责任人 |
对于需要准确确认 LOB 物理段与业务字段对应关系的情况,可以进一步使用DBA_LOBS和DBA_SEGMENTS交叉核验。
九、总结
Oracle 表空间容量分析的核心,是理解数据库的存储机制,并从整体容量逐步定位到具体业务对象。
尤其需要掌握以下基础概念:
LOB = Large Object(大对象)
CLOB、BLOB、NCLOB、BFILE 是不同的 LOB 数据类型。
LOBSEGMENT 是 Oracle 用于存储内部 LOB 数据的物理段,不等于字段本身。
TABLE、INDEX、LOBSEGMENT 可以是同一张业务表关联的不同存储对象。
因此,利用 Toad 排查表空间时,不能只找大表,而应同时关注大索引、大字段及其关联的业务数据。
通过Space → Files → Objects → F4 → Stats/Size这套流程,可以快速完成 Oracle 表空间占用的初步定位,必要时再结合数据字典进行核验。
最终目的不是单纯找出哪个对象最大,而是明确哪些业务数据占用了数据库空间、为什么持续增长,以及需要由哪个业务模块进行整改。
Oracle 19c 官方参考资料
Oracle Large Object 数据类型与基本原理
Oracle SQL 数据类型参考
Oracle LOB 存储机制与 SecureFiles
Oracle DBA_LOBS 数据字典说明
Oracle 数据文件管理