唯一可信的答案是 dba_segments.blocks,它表示表段在数据文件中实际分配的物理块总数,而非已用或估算值。

查 DBA_SEGMENTS 获取表段的物理块数
Oracle 中表占用的物理数据块数量,本质是其段(segment)在数据文件中实际分配的 blocks 数,不是已使用的或空闲的,而是 Oracle 向文件申请并管理的最小单位总数。最直接、最权威的来源就是 DBA_SEGMENTS 视图。
执行前确保你有 SELECT_CATALOG_ROLE 或 DBA 权限;普通用户查不到其他用户的段信息。
示例语句:
SELECT segment_name, segment_type, blocks, bytes/1024/1024 AS mb FROM dba_segments WHERE owner = 'SCOTT' AND segment_name = 'EMP';
-
blocks列即为该段当前分配的物理数据块总数(按DB_BLOCK_SIZE计算) -
bytes是总字节数,可换算成 MB 便于感知大小 - 注意:
segment_name不区分大小写?不,它默认大写,除非建表时加了双引号 - 如果表是分区表,这条语句查的是整个段(含所有分区),不是单个分区 —— 分区信息需查
DBA_TAB_PARTITIONS+DBA_SEGMENTS关联
为什么不能用 NUM_ROWS × AVG_ROW_LEN 估算?
有人试图用行数乘平均行长来反推块数,这在 Oracle 中不可靠,因为:
- 每块有固定开销(cache header、table directory、row directory 等),实际可用空间远小于
DB_BLOCK_SIZE - 存在 PCTFREE、PCTUSED 设置,块内预留空闲空间,影响填充率
- 行迁移(row migration)和链式行(chained rows)会导致单行跨多个块,放大块消耗
- 索引组织表(IOT)、LOB 段、压缩表等结构完全打破“行→块”的线性关系
所以估算值可能偏差 2–5 倍,生产环境排查空间问题必须依赖真实分配值,也就是 DBA_SEGMENTS.BLOCKS。
对比 DBA_EXTENTS 和 DBA_SEGMENTS 的差异
DBA_EXTENTS 记录段的每个区(extent)起始块号与块数,理论上 sum 所有 extent 的 blocks 也能得到总数。但没必要这么绕:
-
DBA_SEGMENTS.BLOCKS是汇总值,查询快、语义明确、一致性高 -
DBA_EXTENTS行数多(尤其小表频繁分配时),sum 容易漏掉条件(比如忘记加segment_name和owner过滤) - 如果段启用了自动段空间管理(ASSM),extents 大小不固定,手工 sum 更易出错
- 极端情况(如段刚 truncate 但未 drop,或延迟段创建未分配),
DBA_SEGMENTS.BLOCKS仍准确反映当前分配状态,而DBA_EXTENTS可能为空
注意 DBA_TABLES.BLOCKS 是统计信息里的“已使用”块数
DBA_TABLES.BLOCKS 看起来名字很像,但它存储的是上一次 ANALYZE 或 DBMS_STATS 收集的“已使用数据块数”,含义完全不同:
- 它是基于采样或全表扫描后统计的 *逻辑使用量*,不含空块、不含高水位线(HWM)以上的块
- 数值可能远小于
DBA_SEGMENTS.BLOCKS,尤其经过大量 DELETE 且未 SHRINK - 该值依赖统计信息是否及时更新;过期统计下它可能为 0 或严重失真
- 它不包含索引、LOB、溢出段等附属段的空间 —— 而
DBA_SEGMENTS查的是整个段对象
真正要回答“这张表占了多少物理块”,唯一可信的答案只有 DBA_SEGMENTS.BLOCKS。别被名字误导,也别混用视图。











