DBA_SEGMENTS是查用户段空间分布最直接入口,需按segment_type+tablespace_name分组定位资源倾斜,注意权限、NULL表空间含义及分区表关联处理。
dba_segments 是查用户段空间分布最直接的入口,但直接 group by owner 只能看总量,要“详细分布”,得拆到段类型、表空间、甚至单个对象粒度。
DBA_SEGMENTS 按 segment_type + tablespace_name 分组统计
这是定位资源倾斜的第一步:某个用户是不是把所有大对象都塞进了一个表空间?索引占了比表还多的空间?
执行前确认你有 SELECT 权限 on DBA_SEGMENTS(DBA 或被显式授权):
-
SEGMENT_TYPE常见值包括:'TABLE'、'INDEX'、'LOBSEGMENT'、'TABLE PARTITION'、'INDEX PARTITION'、'LOBINDEX' -
TABLESPACE_NAME为空(NULL)表示该 segment 在临时表空间(如全局临时表),需另查V$TEMPSEG_USAGE - 示例语句(替换
'APP_USER'为实际用户名,全大写):
SELECT segment_type, tablespace_name,
ROUND(SUM(bytes)/1024/1024/1024, 2) AS gb_total
FROM dba_segments
WHERE owner = 'APP_USER'
GROUP BY segment_type, tablespace_name
ORDER BY gb_total DESC;
- 常见异常信号:
-
INDEX占比 > 60%:可能建了冗余索引或未清理历史索引 -
LOBSEGMENT突增但业务没改:CLOB/BLOB 字段被大量写入且未归档 - 同一用户在多个表空间出现
TABLE但只在一个表空间有INDEX:索引创建时指定了不同TABLESPACE,易导致扩容失衡
-
只查“表本身”空间,排除索引和 LOB 的干扰
业务常问:“这张表占多少空间?”——但默认 DBA_SEGMENTS 会把它的索引、LOB 段全算进来。若只想看表数据段(不含索引、不含 LOB 存储段),必须过滤并关联元数据:
-
SEGMENT_TYPE = 'TABLE'只保证是表段,但分区表的每个分区仍是独立 segment,SEGMENT_NAME就是分区名,不是基表名 - 要对齐到逻辑表名,需 JOIN
DBA_TABLES(注意:DBA_TABLES.TABLE_NAME和DBA_SEGMENTS.SEGMENT_NAME在非分区表下一致;分区表下需用DBA_TAB_PARTITIONS关联) - 简化版(仅适用非分区表):
SELECT s.segment_name AS table_name,
ROUND(s.bytes/1024/1024, 2) AS size_mb,
s.tablespace_name
FROM dba_segments s
JOIN dba_tables t ON s.owner = t.owner AND s.segment_name = t.table_name
WHERE s.owner = 'APP_USER'
AND s.segment_type = 'TABLE'
ORDER BY s.bytes DESC;
- 若用户有分区表,且你要精确到每个分区大小,就得用
DBA_TAB_PARTITIONS+DBA_SEGMENTS左连接(PARTITION_NAME对齐),否则会漏掉分区级空间。
USER_SEGMENTS 和权限受限场景下的替代方案
没有 DBA 权限时,USER_SEGMENTS 只能看到当前登录用户自己的 segment,且不暴露 OWNER 字段(因为就是你自己)。此时无法跨用户统计,但可满足自查需求:
- 它字段结构与
DBA_SEGMENTS几乎一致,只是少了OWNER,多了隐含约束WHERE owner = USER - 想按类型汇总自己占用的空间:
SELECT segment_type,
ROUND(SUM(bytes)/1024/1024/1024, 2) AS gb_total
FROM user_segments
GROUP BY segment_type
ORDER BY gb_total DESC;
- 注意:
USER_SEGMENTS不包含回收站(RECYCLEBIN)里的对象 —— 即使你执行了DROP TABLE但没PURGE,那段空间仍被计入,只是不在USER_SEGMENTS中显示。此时真实占用比查询结果高,需手动检查USER_RECYCLEBIN。
真正容易被忽略的是“已分配但未使用”的空间。DBA_SEGMENTS.BYTES 统计的是 extent 分配量,不是数据实际占用量。一张空表建完就占 8MB(默认 initial extent),而 NUM_ROWS * AVG_ROW_LEN 可能是 0。如果发现某用户报表空间用量远高于业务数据量预期,别急着扩容,先查 DBA_EXTENTS 看 extent 是否碎片化,或用 ANALYZE TABLE ... COMPUTE STATISTICS 更新统计信息再对比。











