DBMS_SPACE.SPACE_USAGE返回的BLOCKS是当前被格式化且实际存放过数据的数据库块数,即header有效且至少写入过一次的“活块”,不包括仅分配未格式化或空闲块。
DBMS_SPACE.SPACE_USAGE 返回的 BLOCKS 是已分配但未使用的块?
不是。返回的 blocks 是该段(segment)中**当前被格式化且实际存放数据的数据库块数量**,不包括仅分配未格式化、或格式化但空闲的块。oracle 只对已写入过数据的块做格式化(block header 初始化),space_usage 统计的是这些“活块”——即 header 有效、且至少有过一次数据写入的块。
常见误解是把这当成“已用数据块数”,但它其实更接近“曾被写入过的块数”。如果反复 DELETE + INSERT,块可能被复用,BLOCKS 不会下降;而 TRUNCATE 后再 INSERT,BLOCKS 会重置增长。
- 只适用于本地管理表空间(LMT),字典管理表空间不支持
- 需要 ANALYZE 或 DBMS_STATS 收集过段统计信息(否则可能返回 0 或陈旧值)
- 对 IOT、LOBSEGMENT、分区表的子段需单独调用,不能直接查父表
调用 DBMS_SPACE.SPACE_USAGE 必须填全 7 个参数?
是的,少一个就会报 ORA-06550: wrong number or types of arguments。它没有默认参数,顺序和类型都严格固定。最容易漏的是第 5 个参数 segment_type(如 'TABLE'、'INDEX'),很多人误传成对象类型名(如 'EMP')或小写字符串,导致 ORA-01403(no data found)。
示例正确调用:
DECLARE
l_unformatted_blocks NUMBER;
l_unformatted_bytes NUMBER;
l_fs1_blocks NUMBER; l_fs1_bytes NUMBER;
l_fs2_blocks NUMBER; l_fs2_bytes NUMBER;
l_fs3_blocks NUMBER; l_fs3_bytes NUMBER;
l_fs4_blocks NUMBER; l_fs4_bytes NUMBER;
l_full_blocks NUMBER; l_full_bytes NUMBER;
BEGIN
DBMS_SPACE.SPACE_USAGE(
segment_owner => 'SCOTT',
segment_name => 'EMP',
segment_type => 'TABLE', -- 必须大写、必须匹配字典中的 TYPE
partition_name => NULL,
unformatted_blocks => l_unformatted_blocks,
unformatted_bytes => l_unformatted_bytes,
fs1_blocks => l_fs1_blocks,
fs1_bytes => l_fs1_bytes,
fs2_blocks => l_fs2_blocks,
fs2_bytes => l_fs2_bytes,
fs3_blocks => l_fs3_blocks,
fs3_bytes => l_fs3_bytes,
fs4_blocks => l_fs4_blocks,
fs4_bytes => l_fs4_bytes,
full_blocks => l_full_blocks,
full_bytes => l_full_bytes
);
DBMS_OUTPUT.PUT_LINE('Used blocks (formatted & non-empty): ' || (l_full_blocks + l_fs1_blocks + l_fs2_blocks + l_fs3_blocks + l_fs4_blocks));
END;FS1–FS4 和 FULL 的块数加起来不等于 USER_SEGMENTS.BLOCKS?
正常。USER_SEGMENTS.BLOCKS 是段当前**分配的总块数**(含空闲、未格式化、已格式化但空),而 SPACE_USAGE 中的 FS1–FS4 + FULL 是**已格式化且有剩余空间的块数之和**(按空闲空间比例分档),它们加起来 ≈ 实际“活跃块数”,但永远 ≤ 分配块数。
典型偏差场景:
- 刚 CREATE TABLE 但没 INSERT:USER_SEGMENTS.
BLOCKS≥ 8(初始 extent),但SPACE_USAGE全为 0(没格式化任何块) - 大量 DELETE 后未 SHRINK:USER_SEGMENTS.
BLOCKS不变,但FULL块减少,FS1–FS4增加,总和可能明显小于分配块数 - 启用 ASSM 后,位图块(bitmap block)不计入
SPACE_USAGE统计,只算数据块
想快速看某个表用了多少“真实数据块”,有没有更轻量的方法?
有,但精度不同:SELECT blocks, num_rows, avg_row_len FROM user_tables WHERE table_name = 'EMP' 结合 DBA_SEGMENTS 的 BLOCKS 字段,能估算逻辑使用量(num_rows × avg_row_len / db_block_size),但无法反映行迁移、链式行、PCTFREE 浪费等物理层细节。
DBMS_SPACE.SPACE_USAGE 是唯一能告诉你“哪些块真被写过、写到什么程度”的标准接口。如果你要判断是否值得 SHRINK、或排查高水位线(HWM)卡住问题,它不可替代——只是别指望它返回“实时精确字节数”,它返回的是块级快照,受延迟块清除、延迟段创建等机制影响。
真正容易被忽略的是:它不扫描整个段,而是读取段头和位图块的元数据,所以执行很快;但如果位图块损坏或统计信息严重滞后,结果就不可信——这时得先 ANALYZE TABLE ... VALIDATE STRUCTURE CASCADE,而不是反复重跑 SPACE_USAGE。

















