广告位 · 页头(后台-模块管理-新建模块后替换此区域)

如何编写Oracle数据库运维自动化脚本提升巡检效率?

Oracle数据库的日常运维中,很多高频操作完全不必依赖图形化管理工具。表空间使用率检查、备份文件清理、锁等待分析这些工作,如果每次都用手工SQL或者EM点来点去,既慢又容易遗漏。把逻辑写成脚本并交给crontab定时执行,可以把故障发现时间从用户投诉提前到自动告警。下面按四个典型场景介绍可直接落地的自动化脚本,示例环境为Linux加Oracle 11g及以上版本,多数SQL也能迁移到19c和21c。

如何编写Oracle数据库运维自动化脚本提升巡检效率?

一、表空间使用率监控与告警

表空间使用率是最基础的巡检项。监控逻辑不复杂:从DBA_DATA_FILES中获取每个表空间的数据文件总大小,从DBA_FREE_SPACE中获取可用空间,两者相减再除以总量就能得到使用率。需要注意的是,临时表空间和UNDO表空间要单独处理,因为它们的空间回收机制不同,直接用这组数据字典容易误报。

下面给出的脚本只处理普通数据文件表空间,阈值设置为85%。当使用率超过85%时输出一行记录,Shell脚本判断输出文件不为空就发送邮件告警。阈值可以根据业务情况调整,比如核心库建议设置为80%,历史库则可以放宽到95%。

SET LINESIZE 200
SET PAGESIZE 100
COL tablespace_name FORMAT A30
COL used_percent FORMAT 999.99
SELECT dfs.tablespace_name,
       ROUND((dfs.total_mb - NVL(fs.free_mb,0)) / dfs.total_mb * 100, 2) AS used_percent,
       dfs.total_mb,
       NVL(fs.free_mb,0) AS free_mb
FROM (SELECT tablespace_name, SUM(bytes)/1024/1024 total_mb
      FROM dba_data_files GROUP BY tablespace_name) dfs,
     (SELECT tablespace_name, SUM(bytes)/1024/1024 free_mb
      FROM dba_free_space GROUP BY tablespace_name) fs
WHERE dfs.tablespace_name = fs.tablespace_name(+)
AND ROUND((dfs.total_mb - NVL(fs.free_mb,0)) / dfs.total_mb * 100, 2) > 85
ORDER BY used_percent DESC;
EXIT;

Shell包装脚本里需要先加载oraenv,这样sqlplus命令才能识别正确的实例。如果服务器上只有一个Oracle实例,可以直接设置ORACLE_SID;多实例环境建议把ORACLE_SID作为参数传入,避免脚本写死。邮件发送部分使用mail命令,生产环境如果没有配置sendmail,也可以改成写入日志再通过企业监控平台采集。

#!/bin/bash
export ORACLE_SID=orcl
export ORAENV_ASK=NO
. oraenv
sqlplus -s / as sysdba @/home/oracle/scripts/ts_check.sql > /tmp/ts_alert.log
if [ -s /tmp/ts_alert.log ]; then
  mail -s "表空间使用率告警" dba@ipipp.com < /tmp/ts_alert.log
fi

这个脚本的优点是足够轻量,不依赖任何第三方工具。但也要注意,它只统计已分配数据文件中的实际空间,如果数据文件开启了自动扩展,还需要结合文件系统剩余空间一起判断,否则可能出现表空间使用率不高、但磁盘已经写满的情况。

二、备份文件与归档日志自动清理

备份文件如果只进不出,最终会把备份目录占满,甚至导致归档日志无法写入、数据库挂起。很多生产库都要求归档保留7天,全量备份保留2份,这个策略适合交给RMAN执行。RMAN脚本里的DELETE OBSOLETE会依据配置的保留策略删除过期备份,而DELETE ARCHIVELOG则专门清理已经备份完成的归档日志。

下面的RMAN脚本先删除过期备份,再删除7天前已经备份完成的归档日志,最后执行CROSSCHECK和EXPIRED清理。CROSSCHECK用来核对物理文件是否还存在,标记为EXPIRED后统一删除,避免控制文件和物理文件状态不一致。

#!/bin/bash
export ORACLE_SID=orcl
export ORAENV_ASK=NO
. oraenv
rman target / <<EOF
DELETE NOPROMPT OBSOLETE;
DELETE NOPROMPT ARCHIVELOG ALL COMPLETED BEFORE 'SYSDATE-7';
CROSSCHECK BACKUP;
DELETE NOPROMPT EXPIRED BACKUP;
EXIT;
EOF

归档日志清理不建议用OS层的rm命令直接删除。因为即使归档日志已经写到磁盘,也不代表它已经被备份软件成功备份。RMAN的DELETE ARCHIVELOG COMPLETED BEFORE会在删除前进行确认,安全性更高。对于expdp导出的dmp文件、导出日志这类非RMAN管理文件,可以用find命令按时间清理,比如下面这条删除7天前的导出文件。

find /backup/expdp -type f -name "*.dmp" -mtime +7 -exec rm -f {} \;

如果是Data Guard环境,归档日志清理还要考虑备库是否已经应用完成。可以适当延长保留周期,或者使用RMAN的DELETE ARCHIVELOG ALL COMPLETED BEFORE搭配STANDBY配置,避免删除主库已清理但备库还未接收的日志。这个需要根据实际保护模式做测试。

三、活跃会话与锁等待诊断

数据库响应变慢时,最需要的不是重启,而是先抓一条正在执行的SQL。V$SESSION视图里记录了每个会话的状态、等待事件、等待时长和SQL_ID,按SECONDS_IN_WAIT倒序排列,通常能快速定位到长时间运行的语句。下面SQL只筛选USER类型且状态为ACTIVE的非空闲等待会话,排除SQL*Net message from client这类正常空闲事件。

SET LINESIZE 200
SET PAGESIZE 100
COL sid FORMAT 99999
COL serial# FORMAT 99999
COL username FORMAT A20
COL status FORMAT A10
COL event FORMAT A40
SELECT s.sid, s.serial#, s.username, s.status, s.event, s.seconds_in_wait, s.sql_id
FROM v$session s
WHERE s.type='USER'
AND s.status='ACTIVE'
AND s.wait_class <> 'Idle'
ORDER BY s.seconds_in_wait DESC;
EXIT;

如果怀疑存在锁等待,可以执行下面这条SQL,直接找出被阻塞的会话和阻塞源。BLOCKING_SESSION字段不为空说明该会话正在等待另一个会话释放锁,结合上一个脚本里的SQL_ID,就能从V$SQLAREA中查到具体语句。

SET LINESIZE 200
SET PAGESIZE 100
COL blocking_session FORMAT 99999
COL sid FORMAT 99999
COL event FORMAT A40
SELECT blocking_session, sid, sql_id, seconds_in_wait, event
FROM v$session
WHERE blocking_session IS NOT NULL;
EXIT;

这类脚本可以做成短周期循环抓取,比如每5秒执行一次,连续抓10次,把输出追加到同一个文件。这样即使问题只持续十几秒,也能留下现场数据,比事后分析AWR快照更方便。需要注意的是,频繁查询V$SESSION本身开销很低,但也不要设置成每秒一次,以免在极端高并发下增加额外负担。

四、AWR报告自动生成与性能数据留存

AWR报告是Oracle性能分析最重要的依据,但很多团队只在出现严重性能问题后才想起来手动生成。实际上用DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_HTML函数可以在不进入交互式SQL*Plus的情况下生成HTML格式报告,非常适合每日定时留存。

下面脚本先获取数据库DBID和最新快照ID,然后生成最近两个快照之间的AWR报告,输出到固定目录。这样可以每天凌晨自动出报告,性能出现拐点时也方便回溯历史数据。

#!/bin/bash
export ORACLE_SID=orcl
export ORAENV_ASK=NO
. oraenv
DBID=$(sqlplus -s / as sysdba <<EOF
SET HEADING OFF FEEDBACK OFF
SELECT dbid FROM v\$database;
EXIT;
EOF
)
SNAP_END=$(sqlplus -s / as sysdba <<EOF
SET HEADING OFF FEEDBACK OFF
SELECT MAX(snap_id) FROM dba_hist_snapshot;
EXIT;
EOF
)
SNAP_BEGIN=$((SNAP_END-1))
sqlplus -s / as sysdba <<EOF
SET LONG 1000000 PAGESIZE 0 TRIMSPOOL ON
SPOOL /home/oracle/awr/awr_report_${SNAP_END}.html
SELECT output FROM TABLE(DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_HTML($DBID, 1, $SNAP_BEGIN, $SNAP_END));
SPOOL OFF;
EXIT;
EOF

这里需要注意AWR快照间隔。默认是每小时一次,如果业务高峰集中在某个时间段,可以把快照间隔调整到30分钟甚至更短,但过快会增加后台任务负担。生成的AWR报告文件名带有快照ID,连续执行不会覆盖历史文件,也方便写简单的日志归档策略。

有些生产库没有购买Diagnostics Pack,AWR功能可能受限。这种情况可以考虑使用Statspack替代,脚本思路类似,只是报告函数和底层表不同。无论采用哪种方式,自动留存性能数据都比临时抱佛脚有效得多。

广告位 · 文章底部(后台-模块管理替换此区域)