dba_segments视图显示表实际分配的物理空间大小,反映os已分配字节数而非逻辑数据量,关键字段包括segment_name、owner、bytes等,需权限且应过滤系统用户和非表类型。
查大表物理空间占用:用 dba_segments 看 segment 级真实大小
oracle 里“大表”不等于“行数多”,而是看它实际占了多少数据文件空间。dba_segments 是最直接的入口——它按 segment(表、索引、lob 等)统计分配的物理空间,不含空闲块或高水位线以上未用空间,反映的是 os 层面已分配的大小。
关键字段:SEGMENT_NAME(对象名)、OWNER(属主)、SEGMENT_TYPE(类型)、BYTES(字节数)、BLOCKS(数据块数)、TABLESPACE_NAME(表空间)。
- 必须有
SELECT_CATALOG_ROLE或DBA权限,普通用户查不到DBA_*视图 -
BYTES是已分配总空间,不是实际数据量;一张空表建完就有 64KB(1个 extent),DBA_SEGMENTS会立刻体现 - 如果表带分区,每个分区是独立 segment,会有多行记录,需按
SEGMENT_NAME+PARTITION_NAME聚合
只查普通堆表(排除索引/LOB/分区子段):加 WHERE 过滤条件
默认查 DBA_SEGMENTS 会把索引、LOB 段、物化视图日志等全拉出来,干扰判断。要聚焦“主表本体”,得严格限定类型和命名逻辑。
示例语句:
SELECT owner, segment_name, bytes/1024/1024 AS mb, blocks
FROM dba_segments
WHERE segment_type = 'TABLE'
AND owner NOT IN ('SYS', 'SYSTEM', 'SYSAUX')
AND bytes > 100*1024*1024 -- 大于100MB才关注
ORDER BY bytes DESC;
-
segment_type = 'TABLE'排除索引('INDEX')、LOB('LOBSEGMENT')、临时段('TEMPORARY') - 过滤
SYS等系统用户,避免被数据字典对象刷屏 - 别只按
blocks排序——不同表空间block_size可能不同(如 8K vs 16K),bytes更可靠
为什么 DBA_SEGMENTS 显示的空间比 NUM_ROWS × AVG_ROW_LEN 大很多?
这是最常被误解的一点:DBA_SEGMENTS.BYTES 是分配空间,而 NUM_ROWS × AVG_ROW_LEN 是逻辑数据估算,两者不在同一维度。
- 表有 PCTFREE 设置(默认 10%),每块预留空闲空间,
DBA_SEGMENTS全算进去 - 发生过大量 DELETE 但没
SHRINK SPACE,高水位线没下降,已分配空间不会自动回收 - 存在迁移行(chained rows)或行链接(row migration),单行跨多个块,
AVG_ROW_LEN完全失真 - 索引组织表(IOT)的溢出段(
OVERFLOW)算作独立 segment,主表行数不包含这部分存储
想看真实数据密度,得结合 DBA_TABLES.NUM_ROWS 和 DBA_TABLES.BLOCKS(已使用数据块数),再对比 DBA_SEGMENTS.BLOCKS(已分配块数)算碎片率。
查完发现某张表占了 50GB,但 SELECT COUNT(*) 很快——说明什么?
这恰恰暴露了空间浪费的典型信号:分配了大量空间,但实际数据稀疏或长期未维护。
- 先确认是否启用了
ASSM(自动段空间管理):如果是,DBA_SEGMENTS.BLOCKS减去DBA_EXTENTS.BLOCKS总和,差值就是 bitmap 块开销(通常很小) - 运行
ANALYZE TABLE ... LIST CHAINED ROWS检查链式行——严重时单行占几十块 - 执行
SELECT * FROM TABLE(DBMS_SPACE.SPACE_USAGE('OWNER','TABLE_NAME','TABLE'))获取更细粒度的已用/未用块分布 - 真正清理前,务必确认归档模式、闪回设置、是否有应用依赖高水位线行为(如某些分页 SQL 用
ROWID范围扫描)
空间回收不是删数据就完事,ALTER TABLE ... SHRINK SPACE COMPACT 需要行移动权限,且期间表不可 DML;如果业务不能停,只能靠定期 MOVE + REBUILD INDEX 分步处理。










