导出v$active_session_history原始数据不可行,需通过alter system set events触发ashdump获取内存快照,再解析trace文件提取ASH数据并清洗入库。
直接导出 v$active_session_history 的原始数据不可行——它只是内存中循环缓冲区的实时视图,重启或缓冲区覆写后历史就丢失了。真要离线分析,得走“dump → trace → 导入临时表”这条路径。
用 alter system set events 'immediate trace name ashdump level N' 触发 dump
这是唯一能固化 ASH 内存快照的方式。level 参数不是秒数,而是**最近 N 分钟**的采样数据(注意:不是精确 N 分钟,是尽力而为):
- level 10 ≈ 最近约 10 分钟的 ASH 数据(实际受 SGA 中 ASH buffer 剩余空间影响)
- level 60 是常用上限,再高可能因 buffer 不足而截断
- 执行后不会报错或提示成功,必须立刻查 trace 路径,否则数据可能被后续 dump 覆盖
定位并提取 trace 文件里的 ASH 数据块
dump 生成的 trace 文件里混着三类内容:头部信息、导入脚本说明、真正的 ASH 行数据。不能直接用 sqlldr 全量加载,必须先剥离有效数据段:
- 先用
v$diag_info查路径:SELECT value FROM v$diag_info WHERE name = 'Default Trace File'; - 用
sed截取中间数据块(示例命令):sed -n '/^ASH DUMP/,/^END OF ASH DUMP/p' ora11g_ora_7556.trc | sed '/^ASH DUMP\|^END OF ASH DUMP/d' > ash_data.txt - 别信 trace 里自带的
sqlldrcontrol file 生成命令——它依赖特定格式的分隔符,Oracle 11g 的 ashdump 输出常含不规则空格和换行,直接套用大概率失败
建临时表 + 手动清洗后批量插入
ASh dump 数据字段顺序固定但无列名,且部分字段为空或含特殊字符(如 #、@),sqlldr 容易解析失败。更稳的做法是建宽表+逐行处理:
- 建表语句建议用:
CREATE TABLE ash_dump_raw (line VARCHAR2(4000));,先全当字符串塞进去 - 再用 PL/SQL 或外部脚本(如 Python)按字段位置切分:第1-10位是
SAMPLE_ID,11-20位是SESSION_ID……具体偏移量需对照 trace 中任意一行实际对齐 - 清洗掉非法字符(如嵌入的换行、制表符)、转义单引号,再 INSERT 到结构化表(如
CREATE TABLE ash_offline AS SELECT * FROM dba_hist_active_sess_history WHERE 1=0;)
最易被忽略的一点:dump 出来的数据里 SQL_ID 和 EVENT 可能被截断(尤其长 SQL 或自定义等待事件),如果后续要关联 dba_hist_sqltext 或过滤特定事件,务必在清洗阶段校验字段长度是否足够——Oracle 11g 的 ashdump 默认只保留前 13 个字符的 SQL_ID,不够时会补 ...,这点不检查,分析就跑偏了。











