正确方法是关联DBA_TAB_PARTITIONS与DBA_SEGMENTS:用t.partition_name = s.segment_name且s.segment_type = 'TABLE PARTITION',再按表名、分区名聚合SUM(s.bytes)并转MB;不可直接用segment_name等于表名或遗漏segment_type过滤,否则结果失真。
查分区表各分区大小,不能直接用 dba_segments 的 segment_name 等于表名——因为分区表的每个分区在 dba_segments 中是独立 segment,segment_name 是分区名,不是表名。
查分区名和对应 segment_name 必须关联 DBA_TAB_PARTITIONS
分区名(PARTITION_NAME)存在 DBA_TAB_PARTITIONS,但它的大小信息不在该视图里;真实存储大小在 DBA_SEGMENTS,且其 segment_name 字段存的就是分区名,segment_type = 'TABLE PARTITION' 或 'INDEX PARTITION'。所以必须靠 PARTITION_NAME 关联两个视图:
-
DBA_TAB_PARTITIONS提供table_name、partition_name、high_value、num_rows等元数据 -
DBA_SEGMENTS提供segment_name(= 分区名)、bytes、tablespace_name - 连接条件是
t.partition_name = s.segment_name,且s.segment_type = 'TABLE PARTITION'
正确 SQL:按表+分区聚合 bytes 并转 MB
以下语句能准确列出指定分区表(如 AI_TOOLS)下所有分区的大小(含空分区),单位 MB,四舍五入到小数点后 2 位:
SELECT t.table_name, t.partition_name, ROUND(SUM(s.bytes) / 1024 / 1024, 2) AS size_mb FROM dba_tab_partitions t JOIN dba_segments s ON t.partition_name = s.segment_name AND s.owner = t.table_owner AND s.segment_type = 'TABLE PARTITION' WHERE t.table_name = 'AI_TOOLS' AND t.table_owner = 'NEW_USER' GROUP BY t.table_name, t.partition_name ORDER BY size_mb DESC;
注意点:
- 表名和 owner 必须大写(Oracle 数据字典默认大写存储)
- 如果只查当前用户对象,把
dba_*换成user_*,去掉owner关联条件 -
SUM(s.bytes)是必须的——一个分区可能有多个 extent,DBA_SEGMENTS每行是一段 extent - 没数据的分区(empty partition)仍会出现在
DBA_TAB_PARTITIONS,但若从未分配 extent,则不会出现在DBA_SEGMENTS,此时该分区 size_mb 为 NULL(可加NVL补 0)
常见错误:误用 segment_name = 表名 或漏掉 segment_type 过滤
这两个错误会导致结果完全失真:
- 写成
WHERE s.segment_name = 'AI_TOOLS'→ 查到的是整张表的 segment(类型为TABLE),不是分区 - 漏掉
AND s.segment_type = 'TABLE PARTITION'→ 会混入该表的索引分区、LOB 分区甚至其他同名 segment,size 被严重高估 - 用
user_segments却没权限查分区 → 返回空,不是没分区,是视图没暴露 - 用
dba_extents聚合但没按segment_name分组 → 每行是单个 extent,不聚合就看不出分区总大小
扩展:带子分区(SUBPARTITION)的场景怎么处理
如果是组合分区(比如 RANGE-LIST),子分区才是物理 segment 单位,此时要查 DBA_TAB_SUBPARTITIONS 和 DBA_SEGMENTS 关联:
-
DBA_SEGMENTS.segment_name对应的是子分区名(SUBPARTITION_NAME),不是分区名 - 连接字段是
s.segment_name = sp.subpartition_name,且s.segment_type = 'TABLE SUBPARTITION' - 若想“按主分区汇总”,需先 JOIN 到
DBA_TAB_PARTITIONS,再 GROUP BYpartition_name
真正容易被忽略的是:一个分区表可能同时存在 TABLE PARTITION(非组合分区)和 TABLE SUBPARTITION(组合分区)两类 segment,查的时候必须明确目标粒度——你要的是“分区级”还是“子分区级”大小。


















