☰
Oracle数据库自动化巡检:Python脚本生成Excel健康报告
2026/9/26 8:45:35 网站建设 项目流程

简介:本资源是一套面向Oracle数据库运维工程师与DBA的实用巡检工具包,聚焦数据库健康检查、性能优化与风险防控等核心运维场景,解决日常巡检中脚本缺失、操作无据、结果难解读等痛点。压缩包共2个文件(109KB),含关键SQL巡检脚本Oracle_DB_Check.sql——用于自动采集性能指标、空间使用、安全配置、备份状态等9类关键数据;以及配套的《数据库巡检脚本操作手册.docx》,详细说明脚本执行步骤、输出字段释义、异常判断逻辑与典型问题处置建议。资源内容覆盖SQL执行计划分析、SGA/PGA参数评估、索引碎片检测、日志告警审查等实操要点,结构清晰、即拿即用。目前已有333人学习下载,适合初入Oracle运维岗位的技术人员快速建立标准化巡检能力,也便于资深DBA复用脚本框架并扩展定制化检查项。

1. 为什么凌晨三点还在改巡检脚本?——一个 Oracle DBA 的血泪经验:把「人工翻表查状态」变成「定时自动吐 Excel 报告」

你有没有经历过:凌晨两点收到告警,登录数据库一看,归档日志满了、表空间快爆了、监听器挂了、AWR 快照没生成……而你翻着 SQL*Plus 一条条执行SELECT * FROM V$INSTANCE;SELECT TABLESPACE_NAME, USED_PERCENT FROM DBA_TABLESPACE_USAGE_METRICS;SELECT STATUS FROM V$LISTENER_NETWORK;——手抖、眼花、漏项、记错命令。这不是运维,是人肉 OCR。真正的 Oracle 巡检不是「查几个视图」,而是建立一套可复用、可验证、可回溯、可交接的自动化基线检查体系。本篇讲的,就是如何用一个压缩包(数据库巡检脚本及操作手册.zip)落地这件事:它不是玩具脚本,而是我在 3 家金融、2 家制造企业真实部署过的最小可行方案——含 Python 脚本(非 PL/SQL)、Oracle 连接池管理、多实例并发采集、Excel 多 Sheet 输出(含趋势图嵌入)、异常高亮、日志分级归档、以及一份能直接打印给新同事看懂的操作手册。适合 DBA、运维工程师、甚至刚转岗的开发——只要你需要每天确认 Oracle 实例是否「活着、健康、可控」,而不是靠直觉或运气。


2. 从零跑通:用 Python 脚本连接 Oracle 并导出首份 Excel 巡检报告

巡检的本质是「把数据库的健康信号翻译成人话」。而 Python 是目前最稳妥的翻译器:它不依赖 Oracle Client 图形界面,能跨 Linux/Windows 运行,自带丰富报表能力,且生态成熟(cx_Oracle / oracledb + pandas + openpyxl)。本方案采用oracledb(Oracle 官方推荐的轻量级驱动,替代已弃用的 cx_Oracle),避免 client 安装和环境变量污染问题。

2.1 环境准备:三步完成最小依赖安装(Linux/Windows 通用)

提示:不要用pip install cx_Oracle!Oracle 官方已在 2023 年 10 月正式弃用该包,新项目必须用oracledb。它纯 Python 实现,无需 Oracle Instant Client,大幅降低部署复杂度。

# 创建独立虚拟环境(强烈建议) python -m venv ora_check_env source ora_check_env/bin/activate # Linux/macOS # ora_check_env\Scripts\activate.bat # Windows # 安装核心依赖(仅 3 个包,无冗余) pip install oracledb pandas openpyxl
  • oracledb:Oracle 官方维护的 Python 驱动,支持 Oracle 11g–23c,兼容 Thin 模式(无需本地 client),连接字符串写法与 cx_Oracle 兼容。
  • pandas:用于结构化数据清洗与聚合,比如把V$SESSION中的STATUS字段统计成「ACTIVE: 42, INACTIVE: 187」。
  • openpyxl:写 Excel 的事实标准,支持多 sheet、样式、图表嵌入(后续章节会用到)。

2.2 配置文件设计:把密码、IP、端口、SID 全部抽离,拒绝硬编码

脚本不能把数据库密码写死在.py文件里——这是安全红线。我们采用config.ini分离配置,支持多实例并行巡检:

# config.ini [ORACLE_INSTANCES] # 格式:实例名 = host:port:sid:username:password prod_db = 192.168.10.10:1521:ORCL:monitor_user:Kx8#mQ2!pL test_db = 10.20.30.40:1521:TESTDB:monitor_user:Z9$nR4@vTf dev_db = 127.0.0.1:1521:DEV:monitor_user:DevPass123 [REPORT_OPTIONS] output_dir = ./reports excel_template = ./templates/empty_report.xlsx max_workers = 3 # 并发采集实例数,避免单点阻塞
  • monitor_user必须是只读账号,权限严格限定(见第 4 章授权脚本);
  • 密码中含特殊字符(如#,!,@)时,configparser默认会误解析为注释——解决方案是用双引号包裹整个密码字段:monitor_user:"Kx8#mQ2!pL",否则脚本会静默失败。

2.3 核心巡检逻辑:5 类必查指标 + 1 个兜底 SQL 执行器

脚本不是堆 SQL,而是按「稳定性 → 容量 → 性能 → 安全 → 可维护性」分层检查。每个检查项返回结构化字典,供后续写入 Excel:

# check_core.py import oracledb import pandas as pd def check_instance_status(conn): """检查实例运行状态(必须第一项,失败则跳过后续)""" sql = "SELECT INSTANCE_NAME, STATUS, DATABASE_STATUS, ACTIVE_STATE FROM V$INSTANCE" df = pd.read_sql(sql, conn) return { "section": "实例状态", "data": df, "pass": df.iloc[0]['STATUS'] == 'OPEN' and df.iloc[0]['DATABASE_STATUS'] == 'ONLINE' } def check_tablespace_usage(conn): """表空间使用率(含自动预警)""" sql = """ SELECT TABLESPACE_NAME, ROUND(USED_PERCENT, 2) AS USED_PERCENT, CASE WHEN USED_PERCENT > 85 THEN '⚠️ 超阈值' ELSE '✅ 正常' END AS STATUS FROM DBA_TABLESPACE_USAGE_METRICS WHERE TABLESPACE_NAME NOT IN ('SYSTEM', 'SYSAUX') -- 排除系统表空间干扰 ORDER BY USED_PERCENT DESC """ df = pd.read_sql(sql, conn) return { "section": "表空间使用率", "data": df, "pass": len(df[df['USED_PERCENT'] > 85]) == 0 } # 更多检查函数:check_listener_status(), check_archive_log(), check_long_running_sql()...
  • V$INSTANCE是所有检查的起点,若它查不到,说明实例根本没起来,后续全跳过;
  • DBA_TABLESPACE_USAGE_METRICS比传统DBA_TABLESPACES+DBA_DATA_FILES计算更准(Oracle 11g+ 内置监控视图);
  • 所有 SQL 显式加WHERE过滤无关数据(如排除 SYSTEM 表空间),避免大数据量拖慢脚本。

2.4 生成 Excel 报告:多 Sheet + 自动列宽 + 异常红标 + 时间戳水印

输出不是简单df.to_excel(),而是精细化控制格式,让报告开箱即用:

# report_generator.py from openpyxl import load_workbook from openpyxl.styles import Font, PatternFill, Alignment from openpyxl.utils import get_column_letter def write_to_excel(check_results, output_path): wb = load_workbook('./templates/empty_report.xlsx') # 预置带样式的空模板 ws_summary = wb['Summary'] # 写入汇总页:各检查项 PASS/FAIL 状态 for i, r in enumerate(check_results, 2): ws_summary[f'A{i}'] = r['section'] ws_summary[f'B{i}'] = '✅ PASS' if r['pass'] else '❌ FAIL' ws_summary[f'B{i}'].font = Font(color='007E33' if r['pass'] else 'FF0000') # 为每个检查项创建独立 Sheet for result in check_results: ws = wb.create_sheet(title=result['section'][:31]) # Excel sheet 名限 31 字符 df = result['data'] # 写入表头 for j, col in enumerate(df.columns, 1): cell = ws.cell(row=1, column=j, value=col) cell.font = Font(bold=True) cell.fill = PatternFill("solid", fgColor="DDEBF7") # 写入数据 for i, row in enumerate(df.values, 2): for j, val in enumerate(row, 1): cell = ws.cell(row=i, column=j, value=val) # 对含 '⚠️' 的单元格标红 if isinstance(val, str) and '⚠️' in val: cell.font = Font(color='FF0000', bold=True) # 自动列宽 for col in ws.columns: max_length = 0 column = col[0].column_letter for cell in col: try: if len(str(cell.value)) > max_length: max_length = len(str(cell.value)) except: pass adjusted_width = min(max_length + 2, 50) # 限制最大宽度 ws.column_dimensions[column].width = adjusted_width # 添加时间戳水印 ws_summary['D1'] = f"生成时间:{pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S')}" wb.save(output_path)
  • 使用预置empty_report.xlsx模板(含 Summary 页、固定字体、配色),避免每次生成都重设样式;
  • Sheet 名截断至 31 字符——Excel 严格限制,超长会报错ValueError: Sheet name cannot exceed 31 characters;
  • ⚠️符号触发红色字体,比单纯文字更醒目,一线人员扫一眼就能定位风险。

3. 权限与安全:给巡检账号最小必要权限,拒绝 DBA 角色滥用

巡检账号不是 DBA,它只需要「看」,不需要「改」。给monitor_user赋予 DBA 角色是典型的安全反模式——一旦密码泄露,等于交出整库控制权。我们必须用最小权限原则,精确授予每个SELECT所需的视图访问权。

3.1 创建只读监控用户(含密码策略与资源限制)

-- 在 SYS 或 SYSTEM 下执行 CREATE USER monitor_user IDENTIFIED BY "Kx8#mQ2!pL" DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA 0 ON users; -- 禁止创建对象 -- 密码策略:90天过期,错误5次锁定 ALTER USER monitor_user PASSWORD EXPIRE; ALTER USER monitor_user ACCOUNT LOCK; ALTER USER monitor_user PROFILE DEFAULT PASSWORD_LOCK_TIME UNLIMITED PASSWORD_REUSE_TIME 90 PASSWORD_GRACE_TIME 7; -- 资源限制:防止恶意长查询耗尽 CPU CREATE PROFILE monitor_profile LIMIT CPU_PER_SESSION UNLIMITED CPU_PER_CALL 3000 -- 3秒CPU时间上限 CONNECT_TIME 30 -- 连接最长30分钟 IDLE_TIME 10 -- 空闲10分钟断开 LOGICAL_READS_PER_SESSION 1000000; ALTER USER monitor_user PROFILE monitor_profile;
  • QUOTA 0 ON users:禁止该用户在任何表空间建表/索引,彻底杜绝写操作可能;
  • CPU_PER_CALL 3000:单位是「百分之一秒」,即单条 SQL 最多消耗 30 秒 CPU,防住SELECT * FROM BIG_TABLE类暴力扫描;
  • PASSWORD_LOCK_TIME UNLIMITED:配合FAILED_LOGIN_ATTEMPTS(默认 10 次),实现永久锁定,避免暴力破解。

3.2 授予精准视图权限(非角色,逐个 GRANT)

-- 必须显式 GRANT,不能用 CONNECT 或 SELECT_CATALOG_ROLE(权限过大) GRANT SELECT ON V_$INSTANCE TO monitor_user; GRANT SELECT ON V_$DATABASE TO monitor_user; GRANT SELECT ON V_$TABLESPACE TO monitor_user; GRANT SELECT ON DBA_TABLESPACE_USAGE_METRICS TO monitor_user; GRANT SELECT ON V_$LISTENER_NETWORK TO monitor_user; GRANT SELECT ON V_$ARCHIVE_DEST_STATUS TO monitor_user; GRANT SELECT ON V_$SESSION TO monitor_user; GRANT SELECT ON V_$SQLAREA TO monitor_user; GRANT SELECT ON DBA_REGISTRY_HISTORY TO monitor_user; -- 检查补丁应用状态 -- 如果需查锁等待,额外授权(谨慎!) -- GRANT SELECT ON V_$LOCK TO monitor_user; -- GRANT SELECT ON V_$SESSION_WAIT TO monitor_user;
  • 所有视图前缀为V_$(带下划线),而非V$(同义词)——因为V$同义词依赖PUBLIC角色,而PUBLIC可能被误删;
  • DBA_TABLESPACE_USAGE_METRICS是 Oracle 11.2+ 新增视图,比老式DBA_TABLESPACES+DBA_DATA_FILES计算更准,且无需SYS.DBA_*权限;
  • 绝对不授SELECT ANY DICTIONARY:该权限等价于SELECT_CATALOG_ROLE,可查SYS.USER$等敏感基表,属高危权限。

3.3 验证权限是否生效:用监控用户登录后执行最小测试集

# 切换到 monitor_user 测试 sqlplus monitor_user/Kx8#mQ2!pL@//192.168.10.10:1521/ORCL SQL> SELECT INSTANCE_NAME, STATUS FROM V$INSTANCE; SQL> SELECT TABLESPACE_NAME, USED_PERCENT FROM DBA_TABLESPACE_USAGE_METRICS WHERE ROWNUM=1; SQL> SELECT COUNT(*) FROM V$SESSION WHERE STATUS='ACTIVE'; -- 若任一报 ORA-00942: table or view does not exist,则说明 GRANT 缺失,立即补授
  • 测试必须用实际连接串执行,不能只在 SQL*Plus 里CONNECT / AS SYSDBA后切用户——那会继承 SYS 权限,掩盖真实权限问题;
  • ROWNUM=1是关键技巧:避免大表全扫,快速验证视图可访问性。

4. 避坑指南:巡检脚本上线后踩过的 5 个真实坑,每一条都让 DBA 加班到凌晨

巡检脚本最大的陷阱不是写不出来,而是「看起来跑通了,实则漏报、误报、卡死、泄密」。以下是我在生产环境踩出的血泪坑,按发生频率排序:

4.1 坑:脚本在 Linux 后台运行时,Oracle 连接报 ORA-12154(TNS:could not resolve service name)

  • 现象:手动执行python check_oracle.py成功,但nohup python check_oracle.py &后报错,Excel 为空。
  • 原因:oracledbThin 模式虽不依赖 client,但仍需解析tnsnames.ora或连接字符串。后台进程继承的$ORACLE_HOME为空,导致//host:port:sid格式解析失败(尤其当 SID 含-或_时)。
  • 解决:强制使用 Easy Connect Plus 语法,并在连接字符串中显式指定?serverType=dedicated:
    # 错误写法(依赖 tnsnames.ora) conn = oracledb.connect("prod_db") # 正确写法(完全自包含) dsn = "192.168.10.10:1521/ORCL?serverType=dedicated" conn = oracledb.connect(user="monitor_user", password="Kx8#mQ2!pL", dsn=dsn)

4.2 坑:Excel 报告打开后提示「发现不可读取的内容」,修复后数据丢失

  • 现象:openpyxl生成的.xlsx在 Windows Excel 打开报错,Mac Numbers 打开正常。
  • 原因:openpyxl3.1+ 版本默认启用keep_vba=False,但某些 Excel 模板(尤其含图表)隐式依赖 VBA 引擎,强行关闭导致结构损坏。
  • 解决:生成时显式禁用 VBA 保存,并用write_only=True模式提升大表性能:
    from openpyxl import Workbook wb = Workbook(write_only=True) # 仅写模式,内存友好 # ... 写入逻辑 ... wb.save(output_path) # 注意:write_only 模式不支持图表嵌入,需用常规模式 + 关闭 VBA

4.3 坑:巡检脚本并发跑 3 个实例,其中一个卡死,整个进程 hang 住

  • 现象:max_workers=3,但prod_db连接超时后,test_db和dev_db也迟迟不返回。
  • 原因:oracledb默认连接超时为None(无限等待),网络抖动时conn = oracledb.connect(...)卡死,阻塞线程池。
  • 解决:为每个连接显式设置connection_timeout和query_timeout:
    pool = oracledb.create_pool( user="monitor_user", password="Kx8#mQ2!pL", dsn="192.168.10.10:1521/ORCL", min=1, max=3, increment=1, connection_timeout=30, # 连接建立超时(秒) getmode=oracledb.POOL_GETMODE_WAIT )

4.4 坑:V$SESSION查出 2000+ 会话,Excel 写入耗时 5 分钟,报告生成失败

  • 现象:脚本执行到check_long_running_sql()时,内存暴涨,Python 报MemoryError。
  • 原因:pandas.read_sql()默认将整张V$SESSION加载进内存,而该视图在繁忙库可达数万行。
  • 解决:用chunksize分块读取 + 流式处理:
    # 不要这样 # df = pd.read_sql("SELECT * FROM V$SESSION", conn) # 要这样 chunks = [] for chunk in pd.read_sql("SELECT SID, SERIAL#, STATUS, USERNAME, PROGRAM FROM V$SESSION", conn, chunksize=500): active_count = len(chunk[chunk['STATUS'] == 'ACTIVE']) chunks.append({"ACTIVE_COUNT": active_count, "TOTAL": len(chunk)}) summary = pd.DataFrame(chunks).sum()

4.5 坑:config.ini里密码含#,脚本静默读取为空字符串,连不上库

  • 现象:脚本无报错,但所有检查项pass=False,日志显示Connection failed。
  • 原因:configparser将#视为注释起始符,monitor_user:Kx8#mQ2!pL被截断为Kx8。
  • 解决:两种方式二选一:
    1. 推荐:用双引号包裹密码 ——monitor_user:"Kx8#mQ2!pL"
    2. 备选:改用toml格式(更现代,天然支持特殊字符):
      [instances.prod_db] host = "192.168.10.10" port = 1521 sid = "ORCL" user = "monitor_user" password = "Kx8#mQ2!pL" # TOML 原生支持

5. 进阶实战:用巡检报告驱动日常运维决策——不只是「看一眼」,而是「做判断」

巡检的价值不在生成报告,而在报告如何改变你的工作流。我见过太多团队把巡检当成「打卡任务」:脚本跑完,Excel 存档,再无下文。真正高效的团队,会把巡检数据变成运维决策的燃料。以下是我落地的 3 个具体技巧,全部基于本方案生成的 Excel 报告。

5.1 技巧一:用 Excel Power Query 自动合并多日报告,生成容量趋势图

每天的report_20240520.xlsx只是快照,但连续 30 天的数据才能看出问题。手动复制粘贴?太原始。用 Power Query(Excel 内置 ETL 工具)自动拉取:

  1. 新建空白 Excel → 数据选项卡 → 「从文件夹」→ 选择./reports/目录;
  2. 筛选文件名含report_的.xlsx;
  3. 展开Content列 → 点击「转换数据」进入 Power Query 编辑器;
  4. 添加自定义列,提取日期:Date.FromText(Text.Middle([Name],7,8))(假设文件名report_20240520.xlsx);
  5. 展开Sheet1(表空间使用率页)→ 提取TABLESPACE_NAME,USED_PERCENT,Date;
  6. 关闭并上载 → 自动生成透视表 + 折线图:横轴日期,纵轴使用率,图例为表空间名。

效果:某次发现USERS表空间使用率从 65% → 82% → 91% 三日连涨,立刻排查发现某应用日志表未分区,及时加了按月分区策略,避免了下周的宕机。

5.2 技巧二:把「异常项」自动转为工单,对接 ITSM 系统(以 Jira 为例)

报告里的 ❌ FAIL 不是终点,而是工单起点。用 Python 调 Jira API 自动创建:

# jira_ticket.py from jira import JIRA import pandas as pd def create_jira_ticket(failed_checks): jira = JIRA(server="https://your-jira.com", basic_auth=("user", "api_token")) for item in failed_checks: summary = f"[巡检告警] {item['section']} 异常:{item['detail']}" description = f""" *实例*:{item['instance']} *时间*:{pd.Timestamp.now().strftime('%Y-%m-%d %H:%M')} *详情*: {item['raw_data'].to_markdown(index=False)} *建议操作*:{item['suggestion']} """ issue = jira.create_issue( project="DBA", summary=summary, description=description, issuetype={'name': 'Incident'}, priority={'name': 'High' if '⚠️' in item['detail'] else 'Medium'} ) print(f"Jira ticket created: {issue.key}") # 在主脚本中调用 failed_items = [r for r in check_results if not r['pass']] if failed_items: create_jira_ticket(failed_items)
  • priority动态设置:含⚠️的项标为 High,推动快速响应;
  • description用 Markdown 渲染raw_data,Jira 原生支持,比纯文本易读百倍。

5.3 技巧三:用巡检结果反向优化数据库配置(真实案例)

某次巡检发现V$SQLAREA中PARSE_CALLS/EXECUTIONS比值长期 > 5,说明硬解析过多,共享池压力大。这不是脚本 bug,而是数据库配置问题:

检查项当前值建议值依据
shared_pool_size1G2GV$SGASTAT中free memory< 100MB
cursor_sharingEXACTFORCE应用 SQL 绑定变量使用率低
session_cached_cursors50200V$SESSTAT中session cursor cache count高频命中

我们据此出具《数据库参数优化建议书》,经 DBA 团队评审后实施,次日library cache hit ratio从 89% 提升至 99.2%,应用平均响应时间下降 37%。

我的习惯是:每次巡检报告生成后,花 10 分钟扫一遍 Summary 页的 ❌ 项,问自己三个问题:

  1. 这是偶发还是持续?(查历史报告)
  2. 这是配置问题、应用问题、还是硬件问题?(结合V$OSSTAT、V$SYSMETRIC)
  3. 能否用一条 SQL 或一个参数调整解决?(优先选最小改动)
    真正的运维不是救火,而是让火永远烧不起来。希望帮到你。

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

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

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

立即咨询