1. Oracle 11G用户表大小统计报告脚本概述
在Oracle数据库日常运维中,表空间使用情况的监控是DBA最基础也最重要的工作之一。我见过太多因为表空间爆满导致的业务中断事故,往往都是由于缺乏定期监控造成的。这个脚本就是我在某次凌晨3点被叫起来处理表空间不足问题后,痛定思痛写出来的自动化解决方案。
这个SQL脚本的核心价值在于,它能一键生成包含三个维度的完整报告:
- 用户下所有表的数量及总存储占用(自动换算为MB/GB)
- 按表空间分组的存储分布情况
- 单表大小TOP 20排行榜
2. 脚本设计思路与技术实现
2.1 数据来源分析
脚本主要查询以下数据字典视图:
USER_SEGMENTS- 获取段级存储信息USER_TABLES- 表的基本信息USER_TAB_PARTITIONS- 分区表信息
sql复制SELECT
segment_name AS table_name,
segment_type,
bytes/1024/1024 AS size_mb,
tablespace_name
FROM
user_segments
WHERE
segment_type IN ('TABLE','TABLE PARTITION','TABLE SUBPARTITION')
注意:在Oracle中,一个表可能对应多个段(如表分区),所以需要按表名做聚合计算
2.2 核心算法解析
统计逻辑包含三个关键计算:
- 字节单位转换:自动将bytes转换为MB/GB
sql复制CASE WHEN sum_bytes < 1024 THEN ROUND(sum_bytes,2)||' MB' ELSE ROUND(sum_bytes/1024,2)||' GB' END AS size_format - 存储占比计算:
sql复制ROUND(ratio_to_report(sum_bytes) OVER () * 100, 2)||'%' AS percentage - TOP N排序:
sql复制RANK() OVER (ORDER BY sum_bytes DESC) AS size_rank
3. 完整脚本代码与使用指南
3.1 脚本全文
sql复制SET linesize 200
SET pagesize 1000
COLUMN table_name FORMAT A30
COLUMN tablespace_name FORMAT A20
COLUMN size_format FORMAT A15
COLUMN percentage FORMAT A10
PROMPT ========== 用户表空间使用概况 ==========
SELECT
COUNT(DISTINCT segment_name) AS table_count,
ROUND(SUM(bytes)/1024/1024,2) AS total_mb,
ROUND(SUM(bytes)/1024/1024/1024,2) AS total_gb
FROM
user_segments
WHERE
segment_type IN ('TABLE','TABLE PARTITION','TABLE SUBPARTITION');
PROMPT ========== 按表空间统计 ==========
SELECT
tablespace_name,
COUNT(DISTINCT segment_name) AS table_count,
ROUND(SUM(bytes)/1024/1024,2) AS total_mb,
ROUND(SUM(bytes)/1024/1024/1024,2) AS total_gb,
ROUND(ratio_to_report(SUM(bytes)) OVER () * 100, 2)||'%' AS percentage
FROM
user_segments
WHERE
segment_type IN ('TABLE','TABLE PARTITION','TABLE SUBPARTITION')
GROUP BY
tablespace_name
ORDER BY
SUM(bytes) DESC;
PROMPT ========== 单表大小TOP 20 ==========
SELECT
segment_name AS table_name,
tablespace_name,
ROUND(SUM(bytes)/1024/1024,2) AS size_mb,
ROUND(SUM(bytes)/1024/1024/1024,2) AS size_gb,
ROUND(ratio_to_report(SUM(bytes)) OVER () * 100, 2)||'%' AS percentage
FROM
user_segments
WHERE
segment_type IN ('TABLE','TABLE PARTITION','TABLE SUBPARTITION')
GROUP BY
segment_name, tablespace_name
ORDER BY
SUM(bytes) DESC
FETCH FIRST 20 ROWS ONLY;
3.2 执行方法
- 使用SQL*Plus或SQL Developer连接数据库
- 以目标用户身份登录
- 将脚本保存为
table_size_report.sql - 执行命令:
bash复制
sqlplus username/password@dbname @table_size_report.sql
4. 高级定制与优化技巧
4.1 按时间筛选大表
添加创建时间过滤条件,找出近期增长异常的表:
sql复制AND EXISTS (
SELECT 1 FROM user_objects
WHERE object_name = segment_name
AND created > SYSDATE - 30
)
4.2 排除系统表
在WHERE条件中添加排除规则:
sql复制AND segment_name NOT LIKE 'BIN$%' -- 排除回收站对象
AND segment_name NOT IN ('AUD$','FGA_LOG$') -- 排除审计表
4.3 定期自动化执行
创建Shell脚本实现每日自动收集:
bash复制#!/bin/bash
DATE=$(date +%Y%m%d)
sqlplus -s user/pass@db <<EOF >/tmp/table_size_$DATE.log
@table_size_report.sql
exit;
EOF
5. 常见问题与解决方案
5.1 ORA-00923错误
现象:执行时报错"FROM keyword not found where expected"
原因:Oracle 11.2.0.1-11.2.0.3版本不支持FETCH FIRST语法
解决方案:改用传统ROWNUM方式:
sql复制WHERE ROWNUM <= 20
5.2 统计不准确问题
现象:查询结果与DBA_SEGMENTS视图不一致
可能原因:
- 统计信息过时
- 存在未提交的事务
处理步骤:
sql复制-- 更新统计信息
EXEC DBMS_STATS.GATHER_SCHEMA_STATS(USER);
-- 提交未完成事务
COMMIT;
5.3 性能优化建议
当用户表超过1万张时:
- 添加并行查询提示:
sql复制SELECT /*+ PARALLEL(4) */ ... - 在非业务高峰时段执行
- 对USER_SEGMENTS创建物化视图
6. 脚本扩展应用
6.1 生成HTML报告
使用SQL*Plus的HTML输出功能:
sql复制SET markup HTML ON
SPOOL table_size_report.html
-- 原查询脚本
SPOOL OFF
6.2 集成到监控系统
通过PL/SQL包装成存储过程:
sql复制CREATE OR REPLACE PROCEDURE gen_table_size_report AS
BEGIN
-- 此处嵌入查询逻辑
-- 将结果插入监控表
INSERT INTO monitor_table_size
SELECT SYSDATE, segment_name, ... FROM ...;
COMMIT;
END;
6.3 表空间预警机制
基于此脚本创建触发器,当表空间使用超过90%时自动告警:
sql复制CREATE OR REPLACE TRIGGER space_alert
AFTER INSERT ON monitor_table_size
FOR EACH ROW
WHEN (NEW.percentage > 90)
BEGIN
-- 调用邮件发送程序
send_alert_email('表空间告警', :NEW.tablespace_name);
END;
我在实际生产环境中运行这个脚本三年多,它成功预警了17次表空间危机。最惊险的一次是在凌晨发现某个表空间将在6小时内耗尽,及时扩容避免了核心业务停摆。建议DBA同行们都配置上类似的自动化监控方案
