DBA_SEGMENTS是最准确的段物理空间查询视图,需过滤SEGMENT_TYPE为TABLE/INDEX/LOBSEGMENT/LOBINDEX,并排除系统用户,注意BYTES含预分配空间,应结合统计信息综合判断。
查表和索引大小,直接用 DBA_SEGMENTS 就行
只要权限够(select_catalog_role 或 dba 角色),dba_segments 是最准的源头——它反映的是段(segment)在数据文件里实际占了多少物理空间,不是逻辑行数,也不是高水位线以下空闲量。表、索引、lob、分区都算段,所以一条 sql 就能拉出所有对象的大小。
过滤 SEGMENT_TYPE 才不会把临时段或回滚段混进来
默认查 DBA_SEGMENTS 会返回所有段类型,比如 TYPE2_UNDO、TEMPORARY、ROLLBACK,这些跟业务表/索引无关。必须显式限定:
WHERE SEGMENT_TYPE IN ('TABLE', 'INDEX', 'LOBSEGMENT', 'LOBINDEX')
常见错误是只写 'TABLE' 或漏掉 LOBSEGMENT——带 CLOB/BLOB 的表,主表可能才几 KB,但 LOB 段可能占几百 MB,不查它就严重低估。
-
LOBSEGMENT对应 LOB 数据本身,LOBINDEX是它的内部索引,两者都要查 - 分区表每个分区是一个独立段,
SEGMENT_NAME显示的是分区名(如SALES_P2023),不是基表名,需要关联DBA_PART_TABLES或用HIGH_VALUE辅助识别 - 如果只关心“用户创建的对象”,加
AND OWNER NOT IN ('SYS','SYSTEM','XDB','WMSYS'),避免被 Oracle 内部对象干扰
BLOCKS 和 BYTES 别直接当“真实使用量”看
BLOCKS 是分配的 Oracle 数据块数,BYTES 是换算后的字节数,但它包含已分配但未使用的空间(比如 INITIAL 分配了 64K,实际只插了 1 行)。真正“用了多少”,得结合 DBA_TAB_STATISTICS 的 AVG_ROW_LEN × NUM_ROWS 估算,或跑 ANALYZE TABLE ... COMPUTE STATISTICS(12c+ 推荐用 DBMS_STATS)。
- 刚建完空表,
BYTES可能是 65536(1 个区),但NUM_ROWS = 0—— 这说明空间是预分配的,不是真用了 - 索引段的
BYTES包含分支节点和叶节点,但叶节点里有大量DEL_LF_ROWS(已删除但未清理的条目),这时候BYTES偏高,需配合INDEX_STATS看DEL_LF_ROWS / LF_ROWS比例 - 表压缩(
COMPRESS FOR OLTP)后,DBA_SEGMENTS.BYTES是压缩后的物理大小,但DBA_TAB_STATISTICS的AVG_ROW_LEN是解压后的逻辑长度,二者不能直接比
按大小排序时,注意单位统一和 NULL 处理
直接 ORDER BY BYTES DESC 会把 NULL 段(比如某些外部表或物化视图日志)排在最前,干扰判断。更稳妥的是:
ORDER BY NVL(BYTES, 0) DESC
另外,BYTES 数值大,肉眼难读,建议除以 1024² 转 MB,并 ROUND(..., 2):
ROUND(BYTES / 1024 / 1024, 2) AS MB
别用 / 1000 / 1000——Oracle 用二进制单位(KiB/MiB),硬盘厂才用十进制。
- 超过 10GB 的对象,
BYTES是NUMBER类型,但某些客户端(如 SQL Developer 默认设置)可能截断显示,建议显式转TO_CHAR(BYTES, '999,999,999,999') - 如果查出来某张表
BYTES异常小(比如 8192),但NUM_ROWS很大,大概率是用了ASSM+BITMAP块管理,且段头块没统计全,可补查DBA_EXTENTS汇总BLOCKS
DBA_SEGMENTS 给的是“盘子有多大”,DBA_TAB_STATISTICS 和 DBA_INDEXES 才告诉你“里面装了多少东西”。三者对不上,八成是统计信息过期或者对象结构特殊(比如 IOT、域索引、XMLIndex)。










