Oracle日常巡检自动化:Python脚本输出Excel报表与趋势分析
简介这份《数据库巡检方案》文档面向Oracle数据库管理员与运维工程师聚焦日常巡检中实例状态、后台进程、文件系统空间、日志清理、备份恢复、权限安全与性能监控等核心环节帮助读者建立可落地的巡检流程降低数据库运行风险。资源包共1个docx文件约2MB内容以命令示例与检查清单为主涵盖SID确认、SMON/PMON/DBWn等后台进程核查、df与bdf磁盘空间监控、bdump/cdump/udump及监听日志清理策略、alert日志排查、RMAN备份验证等实操要点并给出根目录与备份目录空间告警阈值等判断依据。目前已有136人学习下载适合需要系统梳理巡检步骤、对照命令查漏补缺的初中级DBA参考使用。1. 从一份「数据库巡检方案.docx」说起Oracle 日常巡检到底要盯哪些指标很多团队第一次做 Oracle 巡检都是从一份数据库巡检方案.docx开始的。文档里通常列了一堆检查项表空间使用率、RMAN 备份状态、归档日志空间、会话数、等待事件、告警日志……但真到执行的时候问题就来了——这些指标到底怎么查阈值定多少算异常每天手工敲一遍 SQL 显然不现实写脚本又不知道从哪下手。这份方案要解决的核心问题是把「巡检」从一份静态文档变成一套可重复执行的流程。它适合两类人一是刚接手 Oracle 运维、需要快速建立巡检体系的 DBA二是已经在做巡检但还在手工查、想用 Python 脚本自动输出 Excel 报表的工程师。热词里提到的「基于 python 的 oracle 巡检脚本要求输出 excel 表格」正是这个方向最典型的落地形态。我自己的做法是先明确巡检要覆盖的维度再逐个维度写查询语句最后用脚本串起来输出报表。维度不用贪多抓住表空间、RMAN 备份、归档日志、会话与等待事件、告警日志这五块就能覆盖日常 80% 的风险场景。下面按这个思路从方案设计到脚本实现一步步拆开讲。2. 巡检维度拆解与 SQL 查询设计表空间、RMAN、归档日志怎么查2.1 表空间使用率别只看 DBA_TABLESPACE_USAGE_METRICS表空间告急是最常见的巡检发现项。很多人第一反应是查DBA_TABLESPACE_USAGE_METRICS但这个视图有两个坑一是它只统计段的使用情况不包含数据文件自动扩展的剩余空间二是对于临时表空间数据不准。我一般用下面这条 SQL把数据文件层面的信息也带出来-- 表空间使用率巡检结合数据文件大小与自动扩展配置 SELECT df.tablespace_name, ROUND(df.total_mb, 2) AS total_mb, ROUND(df.total_mb - NVL(fs.free_mb, 0), 2) AS used_mb, ROUND((df.total_mb - NVL(fs.free_mb, 0)) / df.total_mb * 100, 2) AS used_pct, df.autoextensible, ROUND(df.max_mb, 2) AS max_mb FROM ( SELECT tablespace_name, SUM(bytes) / 1024 / 1024 AS total_mb, MAX(autoextensible) AS autoextensible, SUM(CASE WHEN autoextensible YES THEN maxbytes ELSE bytes END) / 1024 / 1024 AS max_mb FROM dba_data_files GROUP BY tablespace_name ) df LEFT JOIN ( SELECT tablespace_name, SUM(bytes) / 1024 / 1024 AS free_mb FROM dba_free_space GROUP BY tablespace_name ) fs ON df.tablespace_name fs.tablespace_name ORDER BY used_pct DESC;这条 SQL 的逻辑是子查询df汇总每个表空间的数据文件总大小和最大可扩展大小子查询fs汇总空闲空间两者关联后算出实际使用率。关键参数是used_pct我一般设两级阈值——超过 80% 标黄预警超过 90% 标红告警。autoextensible字段也要看如果是NO且使用率偏高说明这个表空间没有自动扩展兜底必须尽快处理。注意临时表空间要单独查DBA_TEMP_FILES和V$TEMP_SPACE_HEADER不能直接用上面的 SQL。2.2 RMAN 备份状态最近一次全备是否成功、归档是否积压RMAN 备份是巡检里最容易翻车的地方。热词里「rman 备份老是满」「rman delete archive, from, until, before 区别」说明很多人被归档日志撑爆磁盘的问题困扰过。巡检脚本要查两件事最近一次备份是否成功以及归档日志目录的使用情况。-- 最近 7 天 RMAN 备份任务执行情况 SELECT session_key, input_type, status, TO_CHAR(start_time, YYYY-MM-DD HH24:MI:SS) AS start_time, TO_CHAR(end_time, YYYY-MM-DD HH24:MI:SS) AS end_time, ROUND(elapsed_seconds / 60, 1) AS elapsed_min, output_bytes / 1024 / 1024 / 1024 AS output_gb FROM v$rman_backup_job_details WHERE start_time SYSDATE - 7 ORDER BY start_time DESC;V$RMAN_BACKUP_JOB_DETAILS记录了每次 RMAN 备份的详细信息。重点看status字段——COMPLETED是成功FAILED就是有问题。elapsed_min用来判断备份窗口是否在可接受范围内如果平时 30 分钟跑完的备份突然变成 3 小时可能是数据量增长或者 I/O 瓶颈。归档日志的巡检用这条-- 归档日志生成量与目录使用情况 SELECT TRUNC(completion_time) AS log_date, COUNT(*) AS log_count, ROUND(SUM(blocks * block_size) / 1024 / 1024 / 1024, 2) AS total_gb FROM v$archived_log WHERE completion_time SYSDATE - 7 GROUP BY TRUNC(completion_time) ORDER BY log_date DESC;这个查询按天统计归档日志的生成量和大小。如果某天归档量突然翻倍要排查是不是有大批量 DML 操作或者日志切换过于频繁。结合V$RECOVERY_FILE_DEST查闪回恢复区的使用率就能判断归档是否有积压风险。2.3 会话与等待事件定位「现在到底卡在哪」巡检不只是看历史还要看当前状态。会话数和等待事件是判断数据库实时健康度的关键指标-- 当前会话状态分布 SELECT status, COUNT(*) AS session_count FROM v$session WHERE type USER GROUP BY status; -- TOP 5 等待事件 SELECT * FROM ( SELECT event, total_waits, ROUND(time_waited / 100, 2) AS time_waited_sec, ROUND(average_wait / 100, 4) AS avg_wait_sec FROM v$system_event WHERE wait_class ! Idle ORDER BY time_waited DESC ) WHERE ROWNUM 5;第一条查用户会话的ACTIVE和INACTIVE分布如果ACTIVE会话数长期偏高说明系统负载较重。第二条查非空闲等待事件的前五名time_waited_sec是累计等待时间avg_wait_sec是平均每次等待的耗时。如果db file sequential read排第一且平均等待时间超过 10ms说明索引读存在 I/O 瓶颈。2.4 告警日志那些 SQL 查不到的错误有些问题只能从告警日志里发现比如 ORA-00600 内部错误、归档路径写满、数据文件损坏等。巡检脚本可以用 Python 读取告警日志文件匹配关键字import re from datetime import datetime, timedelta # 告警日志关键字匹配ORA-00600/ORA-07445/ORA-01555 等 ERROR_PATTERNS [ rORA-00600, rORA-07445, rORA-01555, rORA-00257, rORA-16038, rORA-19809, rcorrupt, rfatal, rerror ] def scan_alert_log(log_path, hours24): 扫描最近 N 小时的告警日志返回匹配到的错误行 cutoff datetime.now() - timedelta(hourshours) hits [] with open(log_path, r, errorsignore) as f: for line in f: for pat in ERROR_PATTERNS: if re.search(pat, line, re.IGNORECASE): hits.append(line.strip()) break return hitsERROR_PATTERNS里列的是最常见的严重错误码。ORA-00257是归档区满ORA-01555是快照过旧ORA-00600是内部错误需要提 SR。扫描时间窗口默认 24 小时可以根据巡检频率调整。这个函数返回的是匹配到的原始日志行后续写入 Excel 时按时间排序即可。3. 用 Python 把巡检 SQL 串成自动化脚本连接、执行、输出 Excel3.1 连接 Oracle 的两种方式与选型Python 连 Oracle 常见的有两种cx_Oracle现在叫python-oracledb和SQLAlchemy cx_Oracle。如果只是跑巡检 SQL 输出报表直接用oracledb就够了不需要 ORM 那层抽象。安装命令pip install oracledb openpyxloracledb是 Oracle 官方维护的 Python 驱动支持 thin 模式和 thick 模式。thin 模式不需要安装 Oracle Client直接 pip 装完就能用适合巡检脚本这种轻量场景。连接代码import oracledb # 使用 thin 模式连接无需安装 Oracle Client conn oracledb.connect( usersystem, passwordyour_password, dsn192.168.1.100:1521/ORCLPDB1 ) cursor conn.cursor()dsn的格式是host:port/service_name。如果是 19c 单实例service_name 通常是ORCLPDB1或者你创建 PDB 时指定的名字。连接成功后cursor.execute()执行 SQLcursor.fetchall()拿结果集。3.2 巡检脚本主流程从 SQL 字典到 Excel 报表整个脚本的结构是定义一个巡检项字典每项包含名称、SQL、阈值判断逻辑然后循环执行、收集结果、写入 Excel。import oracledb from openpyxl import Workbook from openpyxl.styles import PatternFill, Font from datetime import datetime # 巡检项定义名称、SQL、告警阈值 CHECK_ITEMS { 表空间使用率: { sql: SELECT df.tablespace_name, ROUND((df.total_mb - NVL(fs.free_mb,0))/df.total_mb*100,2) AS used_pct FROM (SELECT tablespace_name, SUM(bytes)/1024/1024 AS total_mb FROM dba_data_files GROUP BY tablespace_name) df LEFT JOIN (SELECT tablespace_name, SUM(bytes)/1024/1024 AS free_mb FROM dba_free_space GROUP BY tablespace_name) fs ON df.tablespace_name fs.tablespace_name ORDER BY used_pct DESC, warn: 80, critical: 90, pct_col: 1 # 使用率在结果集的第 2 列索引从 0 开始 }, RMAN备份状态: { sql: SELECT session_key, status, TO_CHAR(start_time,YYYY-MM-DD HH24:MI) AS start_time, ROUND(elapsed_seconds/60,1) AS elapsed_min FROM v$rman_backup_job_details WHERE start_time SYSDATE - 7 ORDER BY start_time DESC, warn: None, critical: None, pct_col: None } } def run_checks(conn): 执行所有巡检项返回结果列表 results [] cursor conn.cursor() for name, item in CHECK_ITEMS.items(): try: cursor.execute(item[sql]) columns [desc[0] for desc in cursor.description] rows cursor.fetchall() results.append({ name: name, columns: columns, rows: rows, warn: item[warn], critical: item[critical], pct_col: item[pct_col] }) except Exception as e: results.append({ name: name, columns: [错误信息], rows: [(str(e),)], warn: None, critical: None, pct_col: None }) return resultsCHECK_ITEMS字典是脚本的核心配置。每加一个巡检项只需要在这里加一条 SQL 和对应的阈值。pct_col指定哪一列是百分比数值用于后续的条件格式标色。run_checks函数遍历所有巡检项执行 SQL 并收集结果异常时把错误信息也作为一行结果返回保证脚本不会因为某一条 SQL 失败而整体中断。3.3 Excel 输出与条件格式让异常一眼可见输出 Excel 用openpyxl关键是要给异常数据加颜色标记否则一张几十行的表格没人愿意逐行看。def write_excel(results, output_path): 将巡检结果写入 Excel异常数据标红 wb Workbook() wb.remove(wb.active) # 删除默认 sheet red_fill PatternFill(start_colorFFC7CE, end_colorFFC7CE, fill_typesolid) yellow_fill PatternFill(start_colorFFEB9C, end_colorFFEB9C, fill_typesolid) header_font Font(boldTrue) for item in results: ws wb.create_sheet(titleitem[name][:31]) # sheet 名最长 31 字符 # 写表头 for col_idx, col_name in enumerate(item[columns], 1): cell ws.cell(row1, columncol_idx, valuecol_name) cell.font header_font # 写数据行 for row_idx, row in enumerate(item[rows], 2): for col_idx, val in enumerate(row, 1): ws.cell(rowrow_idx, columncol_idx, valueval) # 条件格式根据阈值标色 if item[pct_col] is not None: pct_val row[item[pct_col]] if isinstance(pct_val, (int, float)): if item[critical] and pct_val item[critical]: for c in range(1, len(item[columns]) 1): ws.cell(rowrow_idx, columnc).fill red_fill elif item[warn] and pct_val item[warn]: for c in range(1, len(item[columns]) 1): ws.cell(rowrow_idx, columnc).fill yellow_fill wb.save(output_path) print(f巡检报表已生成: {output_path})write_excel为每个巡检项创建一个 sheet表头加粗数据行逐列写入。条件格式部分如果pct_col有值且该列数值超过critical阈值整行标红超过warn阈值标黄。这样打开 Excel 一眼就能看到哪些表空间需要处理。主流程串起来if __name__ __main__: conn oracledb.connect(usersystem, passwordxxx, dsn192.168.1.100:1521/ORCLPDB1) results run_checks(conn) today datetime.now().strftime(%Y%m%d) write_excel(results, fdb_inspection_{today}.xlsx) conn.close()整个脚本不到 100 行覆盖了表空间、RMAN 备份两个核心巡检项。要扩展的话在CHECK_ITEMS里加 SQL 就行不用改主流程。4. 巡检脚本落地时的避坑与排查连接、权限、阈值那些事4.1 坑一thin 模式连不上报 DPY-3010现象oracledb.connect()报DPY-3010: connections to this database server version are not supported by python-oracledb in thin mode。原因thin 模式对数据库版本有要求Oracle 11g 及以下不支持12c 以上才可以用 thin 模式。如果目标库是 11g必须切到 thick 模式。解决安装 Oracle Instant Client然后初始化import oracledb oracledb.init_oracle_client(lib_dir/opt/oracle/instantclient_21_3)lib_dir指向 Instant Client 的解压目录。初始化之后再调connect()就会走 thick 模式。4.2 坑二巡检账号权限不够查不到 V$ 视图现象执行V$RMAN_BACKUP_JOB_DETAILS或V$ARCHIVED_LOG时报ORA-00942: table or view does not exist。原因普通用户没有查 V$ 动态性能视图的权限。巡检脚本用的账号需要额外授权。解决用 SYSDBA 给巡检账号授以下权限GRANT SELECT ON v_$rman_backup_job_details TO inspect_user; GRANT SELECT ON v_$archived_log TO inspect_user; GRANT SELECT ON v_$session TO inspect_user; GRANT SELECT ON v_$system_event TO inspect_user; GRANT SELECT ON dba_data_files TO inspect_user; GRANT SELECT ON dba_free_space TO inspect_user; GRANT SELECT ON dba_tablespace_usage_metrics TO inspect_user;注意视图名是V_$而不是V$授权时必须用带下划线的写法。4.3 坑三表空间使用率算出来超过 100%现象巡检报表里某个表空间使用率显示 105%。原因DBA_FREE_SPACE不包含已删除但未回收的空间而DBA_DATA_FILES的bytes是文件当前大小。如果数据文件刚扩展过但空闲空间还没更新就会出现使用率超过 100% 的情况。解决在 SQL 里加LEAST(..., 100)做上限截断或者改用DBA_TABLESPACE_USAGE_METRICS的used_percent字段作为辅助参考。两个数据源交叉验证取更保守的值。4.4 坑四RMAN 备份状态查不到最近记录现象V$RMAN_BACKUP_JOB_DETAILS里最近一次备份是三天前的但运维说昨天刚跑过。原因这个视图只记录通过 RMAN 通道执行的备份。如果用expdp或者文件系统快照做的备份不会出现在这里。另外控制文件如果被重建过历史记录也会丢失。解决巡检脚本里同时检查备份日志文件目录或者查RC_BACKUP_SET需要连接 catalog。没有 catalog 的话至少要在脚本里加一条判断如果最近一次备份超过 48 小时直接标红告警。4.5 坑五Excel 输出中文乱码或 sheet 名截断现象生成的 Excel 打开后中文显示为乱码或者 sheet 名被截断。原因openpyxl默认用 UTF-8 写入一般不会乱码。乱码通常是因为用csv模块输出时没指定编码。sheet 名截断是因为 Excel 限制 sheet 名最长 31 个字符。解决如果输出 CSV加encodingutf-8-sig如果输出 Excel在create_sheet时对名称做[:31]截断。另外巡检项名称尽量控制在 10 个字以内避免截断后看不出是哪个检查项。5. 让巡检方案真正跑起来定时调度与历史趋势对比脚本写完了下一步是让它每天自动跑。Linux 下用 crontab 最简单# 每天早上 7 点执行巡检脚本 0 7 * * * /usr/bin/python3 /opt/scripts/db_inspect.py /var/log/db_inspect.log 21但光跑还不够巡检的价值在于趋势对比。我一般会在脚本里加一个历史记录表每次巡检把关键指标写进去-- 在巡检库中创建历史记录表 CREATE TABLE inspect_history ( id NUMBER GENERATED ALWAYS AS IDENTITY, check_date DATE DEFAULT SYSDATE, item_name VARCHAR2(100), item_key VARCHAR2(200), item_value NUMBER, status VARCHAR2(20) );每次巡检后把表空间使用率、归档日志生成量等数值型指标插入这张表。跑上一两个月后就能用 SQL 查趋势-- 查询某个表空间最近 30 天的使用率变化 SELECT check_date, item_value AS used_pct FROM inspect_history WHERE item_name 表空间使用率 AND item_key USERS AND check_date SYSDATE - 30 ORDER BY check_date;有了趋势数据就能做更聪明的判断。比如某个表空间每天增长 0.5%当前使用率 75%那大概 30 天后就会到 90%——这时候提前扩容比等到告警了再处理从容得多。我自己的习惯是巡检脚本的输出分两部分一部分是当天的 Excel 报表另一部分是写入历史表的数值。Excel 给人看历史表给趋势分析用。跑了半年之后回头看哪些表空间在持续增长、哪些备份窗口在逐渐拉长一目了然。这套东西不复杂但坚持跑下来比任何一次突击检查都管用。希望帮到你。本文还有配套的精品资源点击获取