跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

如何排查表空间被哪个对象占用最多_DBA_SEGMENTS空间分布统计

应优先通过DBA_SEGMENTS计算表空间真实使用率以规避DBA_FREE_SPACE碎片失真,再定位TOP20大段并区分LOB/INDEX等类型,最后关联查询LOB和索引归属表,同时排查临时段与UNDO段异常增长。 查表空间整体使用率:先看“谁最挤”,再深入挖 表空间爆满时,第一反应不是直接翻对象,而是确认哪个表空间真的告急。
dba_free_space
在高碎片场景下统计失真,尤其当使用率超过 90% 时,它可能把大量无法合并的小空闲块算作“可用”,误导判断。这时候必须以
dba_segments
为基准——它反映的是已分配段的真实字节数,不依赖空闲块合并状态。 运行这条 SQL 获取真实使用率(按段计算):
SELECT df.tablespace_name AS "表空间名",
ROUND(SUM(df.bytes)/1024/1024,2) AS "总大小(MB)",
ROUND(SUM(s.bytes)/1024/1024,2) AS "已使用(MB)",
ROUND((SUM(df.bytes)-SUM(s.bytes))/1024/1024,2) AS "剩余空间(MB)",
ROUND(SUM(s.bytes)/SUM(df.bytes)*100,2) AS "使用率(%)"
FROM dba_data_files df
JOIN dba_segments s ON df.tablespace_name = s.tablespace_name
GROUP BY df.tablespace_name
ORDER BY "使用率(%)" DESC;
注意
SUM(s.bytes)
是关键:它绕过了
DBA_FREE_SPACE
的碎片盲区,直接从“已分配”角度算账 如果某表空间显示使用率 98%,但
DBA_FREE_SPACE
报出还有 500MB 空闲,大概率是碎片严重,不能信 定位前 20 大段:聚焦
DBA_SEGMENTS
,别只盯表 很多人查完表空间发现 USERS 占了 95%,就立刻去
DBA_TABLES
找大表——这会漏掉真正吃空间的“隐形大户”。一张带 CLOB 字段的表,其
LOBSEGMENT
和
LOBINDEX
可能比表段本身还大好几倍;一个高频更新的索引,
INDEX
段也可能远超基表。 用这个查询直击表空间内真实空间占用 TOP 20:
SELECT owner, segment_name, segment_type, partition_name,
ROUND(bytes/1024/1024,2) AS "大小(MB)"
FROM dba_segments
WHERE tablespace_name = 'USERS'
ORDER BY bytes DESC
FETCH FIRST 20 ROWS ONLY;
segment_type
必须关注:看到
LOBSEGMENT
、
INDEX
、
TABLE PARTITION
都要单独记下来,不能默认只有
TABLE
才重要 如果结果里出现大量
UNDO
或
TEMPORARY
类型段,说明有长事务或排序操作未结束,得结合
V$TRANSACTION
或
V$TEMPSEG_USAGE
追踪 关联 LOB 和索引:搞清“谁在背后占空间” 查到一个大
LOBSEGMENT
名叫
SYS_LOB0000092320C00005$$
,你肯定不认识——它不会告诉你属于哪张表。同理,一个名字像
IDX_ORD_CUSTID
的索引,你也得确认它是不是真挂载在核心订单表上,还是某个测试表的残留。 查 LOB 所属表:
SELECT l.owner, l.table_name, l.column_name, s.bytes/1024/1024 AS "lob_size_mb"
FROM dba_lobs l
JOIN dba_segments s ON l.segment_name = s.segment_name
WHERE s.tablespace_name = 'USERS' AND s.segment_type = 'LOBSEGMENT';
查索引归属的基表:
SELECT i.owner, i.index_name, i.table_owner, i.table_name, s.bytes/1024/1024 AS "idx_size_mb"
FROM dba_indexes i
JOIN dba_segments s ON i.index_name = s.segment_name AND i.owner = s.owner
WHERE s.tablespace_name = 'USERS' AND s.segment_type = 'INDEX';
特别注意:
dba_lobs
中的
segment_name
和
dba_segments
中的完全一致,这是唯一可靠关联点;别用
table_name
去 join,因为分区表的 LOB 段名不含表名 临时段和 UNDO 段异常增长:容易被忽略的“空间刺客” 有时候你查遍了
TABLE
、
INDEX
、
LOBSEGMENT
,TOP 20 里没一个明显异常,但表空间还在涨——八成是临时段或 UNDO 段在偷偷吃空间。它们不持久,但一次大排序或未提交事务就能瞬间拉高使用率。 查当前活跃临时段:
SELECT s.username, u.segtype, u.contents, u.extents, u.blocks*8/1024 AS "mb_used"
FROM v$sort_usage u
JOIN v$session s ON u.session_addr = s.saddr;
查 UNDO 表空间中长事务:
SELECT s.sid, s.serial#, s.username, t.used_ublk, t.start_time
FROM v$transaction t
JOIN v$session s ON t.ses_addr = s.saddr
WHERE t.start_time < SYSDATE - 1/24; -- 超过 1 小时的事务
临时段不会出现在
DBA_SEGMENTS
里(除非你显式创建了永久临时段),所以必须用
v$sort_usage
;UNDO 段则只在
UNDO
表空间内,若你在 USERS 里看到
UNDO
类型段,说明配置错误,得马上纠正 查清楚不是终点。真正难的是区分:哪些是业务必需的大对象,哪些是可归档的历史分区,哪些是开发留下的测试索引——这些判断没法靠 SQL 给出答案,得翻日志、问业务、看上线记录。空间分析的门槛不在语法,而在知道该怀疑谁、该问什么人。

相关文章