python调用oracle awr报告失败主因是权限不足或awrrpti.sql路径错误;需授予select_catalog_role和execute_catalog_role,显式设置oracle_home,用响应文件传参,查真实快照id而非硬编码时间,邮件发送时正确设置mime类型并base64编码,sqlplus脚本末尾加exit并设超时与stderr捕获。
python 调用 oracle awr 报告失败:awrrpti.sql 找不到或权限不足
oracle awr 报告生成依赖数据库端的 sql 脚本,不是 python 自己能“算出来”的。直接在 python 里用 cx_oracle 执行 select 拿不到完整 awr 报告——它本质是调用 @?/rdbms/admin/awrrpti.sql 这类脚本拼 html 或文本,得靠 sqlplus 命令行驱动。
常见错误现象:SP2-0310: unable to open file "awrrpti.sql" 或 ORA-01031: insufficient privileges。
- 确保目标数据库用户有
SELECT_CATALOG_ROLE和EXECUTE_CATALOG_ROLE(仅DBA不够,角色需显式授予) -
sqlplus必须能访问 Oracle Home 下的$ORACLE_HOME/rdbms/admin/目录,不能只靠环境变量,建议在脚本中显式指定ORACLE_HOME - 别用 Python 的
subprocess.run(['sqlplus', ...])硬编码用户名密码,改用响应文件(awrrpti.sql接受参数输入),避免明文泄露和特殊字符中断
定时生成 AWR 报告时时间范围错乱:begin_snap 和 end_snap 总对不上
AWR 快照不是每小时整点一张,间隔可能被修改过(比如改成 30 分钟采集),也不能假设最近快照就是“昨天”。硬写死 SYSDATE-1 在 awrrpti.sql 里会出错。
- 先用 SQL 查真实快照窗口:
SELECT MIN(snap_id), MAX(snap_id) FROM dba_hist_snapshot WHERE begin_interval_time >= SYSDATE - 1 - 把查到的
min_snap_id、max_snap_id拼进sqlplus的响应文件,而不是让awrrpti.sql自己算 - 注意时区:数据库服务器时区和 Python 所在机器时区不一致时,
SYSDATE结果不同,统一用数据库侧时间逻辑
邮件发送附件乱码或打不开:HTML 报告被当纯文本处理
AWR 生成的是带 CSS 和 JS 的 HTML 文件,但 Python 的 smtplib 默认只发纯文本,附件 MIME 类型设错就会变成一堆源码或下载后空白。
- 用
mimetypes.guess_type()判断.html文件类型,强制设为text/html,别依赖扩展名猜测 - 读取报告文件时必须用
rb模式,再用base64.b64encode()编码,否则二进制内容损坏 - 邮件主题加时间戳,比如
AWR Report - {db_name} - {datetime.now().strftime('%Y%m%d_%H%M')},方便归档和排查重名覆盖
巡检脚本跑着跑着就卡住:sqlplus 进程没退出或超时无响应
sqlplus 是交互式工具,如果 AWR 报告生成慢(比如大库+长周期)、网络抖动、或 SQL 脚本里漏了 EXIT,Python 就一直等子进程结束,整个定时任务挂起。
- 给
subprocess.run()加timeout=300(5 分钟),超时直接杀掉并记录错误日志 - SQL 脚本末尾必须有
EXIT,且前面不能有未捕获的错误跳过它(比如WHENEVER SQLERROR EXIT FAILURE要配好) - 别省略
stderr重定向:把sqlplus的报错输出也捕获到日志里,否则只能看到 “Process timed out”,看不到真正卡在哪一步
AWR 报告生成链路长、依赖多,最容易被忽略的是数据库侧角色授权是否生效(SET ROLE 不等于登录即激活)、以及 sqlplus 启动时的 NLS_LANG 环境变量是否匹配数据库字符集——这两个点一错,报告内容就乱码或截断,但脚本还显示“成功”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










