☰
Oracle数据库巡检脚本与操作手册:从手工翻车到一键出报告的落地路径
2026/10/9 23:26:07 网站建设 项目流程

简介:这份资源面向Oracle数据库运维人员与DBA,提供一套可直接落地的数据库巡检方案,帮助解决性能瓶颈、空间告警、安全隐患等日常运维难题。压缩包共2个文件,包含1个SQL巡检脚本与1份docx操作手册,整体约109KB,脚本负责批量采集数据库状态与关键指标,手册则讲解执行方法与结果解读技巧。内容覆盖性能监控、空间管理、安全性检查、备份恢复策略、参数调整、索引与表维护、日志警报审查等多个维度,读者可据此快速排查慢查询、评估SGA与PGA设置合理性、验证备份可用性,并形成定期巡检的规范流程。目前已有333人学习下载,适合初入行的运维新手对照手册上手,也适合经验丰富的DBA作为巡检清单与排错参考。

1. 数据库巡检脚本及操作手册:从手工翻车到一键出报告的落地路径

凌晨两点被叫起来处理表空间爆满,登录上去发现归档日志把磁盘撑到 100%,这种事我经历过不止一次。后来才想明白,巡检不是等告警响了再去救火,而是每天固定时间把该看的指标扫一遍,把问题掐死在萌芽里。Oracle 数据库巡检脚本及操作手册这套东西,核心就是解决「人工巡检靠记忆、漏项多、报告难写」这三个痛点。它适合两类人:一是手里管着几套 Oracle 实例但没上商业监控的运维,二是需要定期给团队出巡检报告的 DBA。脚本负责采集,手册负责告诉你每个指标的正常范围在哪、异常了怎么处理。整套方案不需要额外买工具,用数据库自带的视图和 SQL*Plus 就能跑起来,落地成本极低。

2. 巡检脚本到底采什么:先搞清楚指标分层再动手写 SQL

2.1 从「救火清单」反推巡检项

很多人写巡检脚本容易犯一个错:把网上抄来的 SQL 一股脑塞进去,跑出来几十个结果集,自己都不知道哪些该重点关注。我的做法是从「救火清单」反推——你过去半年处理过的故障,对应哪些指标?把这些指标列出来,就是巡检的核心项。

常见故障和对应巡检项的关系大致是这样:

故障现象根因指标巡检视图
连接不上会话数打满、进程数超限v$session、v$resource_limit
查询变慢等待事件异常、执行计划突变v$system_event、v$sql
磁盘告警表空间使用率、归档日志增长dba_tablespace_usage_metrics、v$recovery_file_dest
实例宕机告警日志报错、ORA-错误v$diag_alert_ext
备份失败归档空间满、RMAN 作业状态v$rman_backup_job_details

这张表就是巡检脚本的骨架。你不需要一上来就覆盖所有视图,先把这五类跑通,日常 80% 的问题都能提前发现。

2.2 指标分层的三个维度

指标不能平铺,要分层。我一般按「紧急程度」和「变化速度」两个维度分三层:

第一层是红线指标,超了就必须立刻处理,比如表空间使用率超过 90%、归档目录使用率超过 85%、会话数超过参数值的 80%。这些指标的特点是阈值明确、后果严重。

第二层是趋势指标,单次看没问题但趋势不对就要警惕,比如每天归档日志增长量、活跃会话数的日峰值变化、TOP 等待事件的时间占比漂移。这类指标需要和历史数据对比才有意义。

第三层是基线指标,用来建立正常状态的参照,比如参数配置、对象数量、用户权限分布。平时不用天天看,但出问题时可以快速对比「现在和以前有什么不一样」。

分层的好处是脚本输出可以按优先级排序,值班的人先看红线,再看趋势,最后扫一眼基线。不会出现「报告 50 页,重点在哪不知道」的情况。

2.3 用 SQL*Plus 跑通第一个采集脚本

先写一个最小可用的采集脚本,把红线指标跑出来。用 SQL*Plus 的-S静默模式,配合set markup输出成易读格式。

-- check_redline.sql -- 红线指标采集脚本,输出到当前目录的 redline_report.txt set linesize 200 set pagesize 100 set feedback off set trimspool on set markup html on spool on spool redline_report.html -- 1. 表空间使用率超过 90% 的 prompt ===== 表空间使用率告警 ===== select d.tablespace_name, round(d.bytes/1024/1024/1024, 2) as total_gb, round((d.bytes-nvl(f.bytes,0))/1024/1024/1024, 2) as used_gb, round((d.bytes-nvl(f.bytes,0))/d.bytes*100, 2) as used_pct from dba_data_files d left join (select file_id, sum(bytes) bytes from dba_free_space group by file_id) f on d.file_id = f.file_id where (d.bytes-nvl(f.bytes,0))/d.bytes > 0.9 order by used_pct desc; -- 2. 归档目录使用率 prompt ===== 归档目录使用率 ===== select name, round(space_limit/1024/1024/1024, 2) as limit_gb, round(space_used/1024/1024/1024, 2) as used_gb, round(space_used/space_limit*100, 2) as used_pct from v$recovery_file_dest; -- 3. 会话数使用率 prompt ===== 会话数使用率 ===== select resource_name, current_utilization, limit_value, round(current_utilization/limit_value*100, 2) as used_pct from v$resource_limit where resource_name in ('sessions','processes') and current_utilization/limit_value > 0.8; spool off exit

这个脚本的逻辑很直白:三个查询分别对应表空间、归档目录、会话数三个红线指标,每个查询都带了使用率计算和阈值过滤。set markup html on让输出直接是 HTML 表格,省去后期排版。

参数说明:linesize 200防止宽表折行,pagesize 100避免分页符干扰,trimspool on去掉行尾空格。阈值我设的是 90%、85%、80%,你可以根据自己环境的容忍度调整。注意v$recovery_file_dest在非归档模式下可能没有数据,需要先确认数据库是否开启了归档。

执行方式:

sqlplus -S / as sysdba @check_redline.sql

跑完之后当前目录会生成redline_report.html,浏览器打开就能看到告警项。如果三个查询都没有返回行,说明红线指标全部正常。

3. 把采集结果变成可读报告:脚本编排与输出格式化

3.1 用 Shell 做脚本编排

单个 SQL 文件只能解决一个场景,实际巡检需要把多个采集脚本串起来,加上时间戳、环境信息、执行日志。我一般用 Shell 做编排层,SQL 只负责查询。

#!/bin/bash # oracle_inspect.sh # Oracle 巡检主控脚本,按顺序执行各采集模块并汇总 REPORT_DIR="/home/oracle/inspect_reports" DATE_TAG=$(date +%Y%m%d_%H%M%S) REPORT_FILE="${REPORT_DIR}/inspect_${DATE_TAG}.html" mkdir -p ${REPORT_DIR} # 写入报告头部 cat > ${REPORT_FILE} <<EOF <html><head><meta charset="utf-8"> <title>Oracle 巡检报告 ${DATE_TAG}</title> <style> body { font-family: monospace; margin: 20px; } h2 { color: #333; border-bottom: 1px solid #ccc; } table { border-collapse: collapse; margin: 10px 0; } td, th { border: 1px solid #999; padding: 4px 8px; } .warn { background-color: #ffe0e0; } </style></head><body> <h1>Oracle 巡检报告</h1> <p>实例:${ORACLE_SID} 时间:$(date '+%Y-%m-%d %H:%M:%S')</p> EOF # 依次执行各采集模块,追加到报告 for module in redline tablespace session wait_event backup; do echo "<h2>模块:${module}</h2>" >> ${REPORT_FILE} sqlplus -S / as sysdba @${module}.sql >> ${REPORT_FILE} 2>&1 echo "<hr/>" >> ${REPORT_FILE} done echo "</body></html>" >> ${REPORT_FILE} echo "报告已生成:${REPORT_FILE}"

这段脚本的核心思路是「模块化采集、统一汇总」。for循环遍历模块名,每个模块对应一个 SQL 文件,输出直接追加到 HTML 报告里。ORACLE_SID是环境变量,SQL*Plus 会自动读取。

参数说明:REPORT_DIR改成你自己的路径,确保 oracle 用户有写权限。DATE_TAG精确到秒,避免同一天多次巡检覆盖。模块列表可以按需增减,比如加上parameter、object等。

3.2 输出格式化的几个关键点

SQL*Plus 默认输出是纯文本,直接嵌 HTML 会乱。除了前面提到的set markup html on,还有几个参数需要配合:

set markup html on entmap on spool on preformat off set linesize 300 set pagesize 0 set echo off set verify off set heading on

entmap on把特殊字符转义,防止<>破坏 HTML 结构。preformat off让表格正常渲染而不是被<pre>包住。pagesize 0去掉分页,所有结果连续输出。heading on保留列名。

如果某个查询返回空结果,报告里会显示「no rows selected」,这其实是有用信息——说明该项正常。但为了美观,可以在 SQL 里加一个nvl兜底,或者用prompt先输出一行说明。

3.3 加一个「巡检摘要」模块

报告最后应该有一个摘要页,把关键数字汇总成一行,方便快速判断。这个模块不查新数据,而是从前面模块的输出里提取。

-- summary.sql -- 巡检摘要:汇总关键指标 set markup html on prompt <h2>巡检摘要</h2> prompt <table> prompt <tr><th>指标</th><th>当前值</th><th>状态</th></tr> select '<tr><td>表空间告警数</td><td>' || count(*) || '</td><td>' || case when count(*) > 0 then '<span class="warn">需关注</span>' else '正常' end || '</td></tr>' from dba_data_files d left join (select file_id, sum(bytes) bytes from dba_free_space group by file_id) f on d.file_id = f.file_id where (d.bytes-nvl(f.bytes,0))/d.bytes > 0.9; prompt </table>

这个摘要查询只统计告警数量,不展开细节。细节在前面模块里已经有了,摘要的作用是让看报告的人三秒钟判断「今天要不要加班」。

4. 巡检避坑指南:那些手册上不会写的翻车现场

4.1 权限不够导致查询返回空

现象:脚本跑完,报告里所有查询都是「no rows selected」,但数据库明明有问题。

原因:用普通用户执行脚本,没有访问dba_*和v$*视图的权限。SQL*Plus 不会报权限错误,只会静默返回空结果。

解决:巡检脚本统一用sysdba执行,或者给巡检用户授予select any dictionary和select any table权限。执行前先跑一句select count(*) from dba_data_files;确认权限正常。

4.2 归档目录查询在非归档模式下报错

现象:脚本执行到归档模块时中断,后续模块全部没跑。

原因:v$recovery_file_dest在非归档模式下可能不存在或返回 ORA-错误,SQL*Plus 默认遇到错误继续执行,但如果用了whenever sqlerror exit就会中断。

解决:在脚本开头加whenever sqlerror continue,或者在归档模块前先判断log_mode:

select log_mode from v$database; -- 如果返回 NOARCHIVELOG,跳过归档模块

4.3 报告文件越来越大,打开卡死

现象:巡检跑了三个月,报告文件积累了几百个,单个文件也有几十 MB,浏览器打开直接卡死。

原因:每次巡检都生成完整报告,历史报告没有清理,且某些查询返回行数过多(比如v$sql没加过滤条件)。

解决:两个措施。一是加清理逻辑,只保留最近 30 天的报告:

find ${REPORT_DIR} -name "inspect_*.html" -mtime +30 -delete

二是给所有查询加rownum限制,比如where rownum <= 50,避免单个模块输出爆炸。

4.4 时间戳时区不对导致报告排序混乱

现象:报告文件名的时间戳和实际执行时间差 8 小时,按文件名排序时顺序错乱。

原因:数据库服务器和巡检脚本执行机器的时区不一致,date命令取的是系统时区。

解决:在脚本里显式指定时区,或者统一用 UTC 时间戳:

DATE_TAG=$(TZ='Asia/Shanghai' date +%Y%m%d_%H%M%S)

4.5 巡检期间锁表影响业务

现象:巡检脚本跑的时候,业务反馈某些操作变慢。

原因:某些查询(比如查dba_free_space)在大表空间上可能持有 latch,或者查询v$session时和业务会话产生竞争。

解决:巡检脚本安排在业务低峰期执行,比如凌晨 4 点。如果必须在高峰期跑,给查询加/*+ rule */提示走规则优化器,减少对共享池的冲击。更稳妥的做法是配置一个 Data Guard 备库,巡检全部在备库上跑。

5. 让巡检从「一次性脚本」变成「日常习惯」的两个进阶技巧

5.1 用对比法发现「慢变化」问题

单次巡检只能看到「现在是什么样」,对比历史才能发现「正在往哪个方向变」。我一般会在巡检脚本里加一个「与上周同期对比」的模块,把关键指标的变化率算出来。

-- trend_compare.sql -- 对比当前表空间使用率和 7 天前的记录 -- 假设有一个 inspect_history 表存储历史快照 select t.tablespace_name, t.used_pct as today_pct, h.used_pct as last_week_pct, round(t.used_pct - h.used_pct, 2) as diff_pct from (select tablespace_name, round((d.bytes-nvl(f.bytes,0))/d.bytes*100, 2) as used_pct from dba_data_files d left join (select file_id, sum(bytes) bytes from dba_free_space group by file_id) f on d.file_id = f.file_id) t join inspect_history h on t.tablespace_name = h.tablespace_name where h.snap_date = trunc(sysdate) - 7 and abs(t.used_pct - h.used_pct) > 5 order by diff_pct desc;

这个查询的关键是inspect_history表,需要你先建好并每天插入快照。建表语句很简单:

create table inspect_history ( snap_date date, tablespace_name varchar2(30), used_pct number(5,2) ); -- 每天巡检后插入快照 insert into inspect_history select trunc(sysdate), tablespace_name, round((d.bytes-nvl(f.bytes,0))/d.bytes*100, 2) from dba_data_files d left join (select file_id, sum(bytes) bytes from dba_free_space group by file_id) f on d.file_id = f.file_id; commit;

有了历史数据,你就能回答「这个表空间是按什么速度在增长」「照这个趋势还能撑几天」这类问题。这比单次巡检有价值得多。

5.2 把巡检结果推送到值班群

报告生成之后,如果没人看等于白跑。我的做法是把摘要部分提取出来,通过企业微信或钉钉的机器人接口推送到值班群。不需要推完整报告,只推红线指标和趋势异常项。

#!/bin/bash # notify.sh # 提取巡检摘要并推送到值班群 REPORT_FILE=$1 WEBHOOK_URL="https://your-webhook-url" # 提取摘要部分(假设摘要模块输出在 <h2>巡检摘要</h2> 之后) SUMMARY=$(sed -n '/巡检摘要/,/<\/table>/p' ${REPORT_FILE} | sed 's/<[^>]*>//g') # 构造推送内容 CONTENT="Oracle 巡检摘要\n${SUMMARY}\n完整报告:${REPORT_FILE}" # 发送 curl -s -X POST ${WEBHOOK_URL} \ -H "Content-Type: application/json" \ -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"${CONTENT}\"}}"

这个脚本用sed从 HTML 报告里提取纯文本摘要,然后通过 webhook 推送。WEBHOOK_URL换成你自己的机器人地址。注意sed的正则匹配依赖报告结构,如果摘要模块的 HTML 标签变了,提取逻辑也要跟着改。

我自己的习惯是:巡检脚本每天凌晨 4 点由 crontab 自动执行,生成报告后自动推送摘要到值班群。值班的人早上到工位第一件事就是看群里的摘要,有告警就点开完整报告定位。这套流程跑了两年多,最明显的变化是「凌晨被叫起来」的次数从每月两三次降到了半年一次。脚本不复杂,关键是坚持跑、坚持看、坚持对比。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询