作者简介:洪杰贤,瑞蓝创数据库工程师
原创内容未经授权不得随意使用,转载请联系小编并注明来源
一、什么是 ASH?
ASH(Active Session History,活跃会话历史)是 OceanBase 提供的一种基于采样的会话性能诊断工具。它以固定频率(默认每 1 秒)对数据库中所有活跃会话的状态进行快照采样,将采样结果持久化存储,形成一条"会话状态时间线"。
ASH 的核心理念来源于 Oracle Database 的 ASH(Active Session History),OceanBase 从 V4.x 开始支持这一能力,使其在不需要全程追踪(Trace)的情况下,也能事后回溯分析性能问题。
与其他诊断工具的关系
|
|
|
|
|
|---|---|---|---|
| SQL Audit |
|
|
|
| Trace(show trace) |
|
|
|
| ASH |
|
|
时间段内的系统级性能回溯 |
| AWR |
|
|
|
ASH 填补了 SQL Audit(只看完成后的统计)和 Trace(只看单条 SQL)之间的空白:它让你能回到任意历史时刻,看那时系统在忙什么、等什么。
二、ASH 的工作原理
2.1 采样机制
时间轴 →
──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──→
│ │ │ │ │ │ │ │ │ │
S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 ← 每秒采样一次
每个采样点记录:
Session ID
Tenant ID
SQL ID
Wait Event
Wait Class
Time in Wait (ms)
CPU Time (ms)
SQL Text (片段)
Plan ID
Module / Client Info
Sample Time
OceanBase 后台线程以 1 秒 的采样间隔扫描所有 Observer 上的活跃线程(正在执行 SQL 或正在等待的线程),记录其当前状态。这意味着:
-
不是每条 SQL 都被完整记录——采样到哪条就在那个瞬间记录哪条 -
采样频率固定——目前每秒一次(可控) -
数据代表"概率分布"——如果某条 SQL 执行了 100 秒,大约会被采样到 100 次
2.2 存储结构
ASH 采样数据存储在内部视图中:
-
DBA_ACTIVE_SESSION_HISTORY 全局视图(所有租户) -
GV$ACTIVE_SESSION_HISTORY 集群级实时视图(内存中,几小时内) -
V$ACTIVE_SESSION_HISTORY 当前节点实时视图
数据保留策略:
-
内存中保留最近的活跃会话历史(通常数小时,取决于内存配额) -
可通过 CALL DBMS_WORKLOAD_REPOSITORY.ASH_REPORT(...)生成报告 -
AWR 快照会自动保存 ASH 数据的聚合结果
2.3 采样内容详解
每次采样记录的核心字段:
|
|
|
|
|---|---|---|
SAMPLE_TIME |
|
|
SESSION_ID |
|
|
TENANT_ID |
|
|
SQL_ID |
|
|
WAIT_EVENT_ID |
|
核心字段
|
WAIT_CLASS |
|
|
TIME_WAITED |
|
|
PROGRAM |
|
|
MODULE |
|
|
PLAN_ID |
|
|
EVENT_NAME |
|
|
三、如何使用 ASH
3.1 直接查询 ASH 视图
最直接的方式——查 GV$ACTIVE_SESSION_HISTORY 视图:
-- 查看最近 30 分钟内最活跃的 SQL
SELECT SQL_ID,
COUNT(*) AS sample_count,
ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 2) AS pct_of_samples
FROM GV$ACTIVE_SESSION_HISTORY
WHERE SAMPLE_TIME >= NOW() - INTERVAL 30 MINUTE
GROUP BY SQL_ID
ORDER BY sample_count DESC
LIMIT 10;
-- 查看最近 1 小时内的等待事件分布
SELECT WAIT_CLASS,
EVENT_NAME,
COUNT(*) AS wait_count,
ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 2) AS pct
FROM GV$ACTIVE_SESSION_HISTORY
WHERE SAMPLE_TIME >= NOW() - INTERVAL 1 HOUR
GROUP BY WAIT_CLASS, EVENT_NAME
ORDER BY wait_count DESC
LIMIT 20;
-- 查看某个时间段内最活跃的会话
SELECT SESSION_ID,
PROGRAM,
MODULE,
COUNT(*) AS active_samples,
SUM(CASEWHEN WAIT_CLASS = 'CPU'THEN1ELSE0END) AS cpu_samples,
SUM(CASEWHEN WAIT_CLASS != 'CPU'THEN1ELSE0END) AS wait_samples
FROM GV$ACTIVE_SESSION_HISTORY
WHERE SAMPLE_TIME BETWEEN'2026-07-23 08:30:00'AND'2026-07-23 12:00:00'
GROUPBY SESSION_ID, PROGRAM, MODULE
ORDERBY active_samples DESC
LIMIT20;
3.2 生成 ASH 报告
OceanBase 提供了内置的 ASH 报告生成函数,输出格式化的分析报告:
-- 基本用法:指定时间范围
CALL DBMS_WORKLOAD_REPOSITORY.ASH_REPORT(
'2026-07-23 08:30:00', -- 开始时间
'2026-07-23 12:00:00' -- 结束时间
);
执行后系统会返回一个报告 URL 或直接输出报告内容,包含以下分析模块:
1. 概要信息(时间范围、采样总数、活跃会话数)
2. Top SQL(采样最多的 SQL)
3. Top 等待事件
4. Top 会话
5. 等待事件随时间分布
6. SQL → 等待事件关联
7. 租户级负载分布
3.3 带过滤条件的 ASH 报告
-- 只分析某个租户的 ASH 数据
CALL DBMS_WORKLOAD_REPOSITORY.ASH_REPORT(
'2026-07-23 08:30:00',
'2026-07-23 12:00:00',
tenant_id => tenant_id
);
-- 只分析某个 SQL_ID
CALL DBMS_WORKLOAD_REPOSITORY.ASH_REPORT_FILTER(
'2026-07-23 08:30:00',
'2026-07-23 12:00:00',
sql_id => 'sql_id'
);
提示:具体函数签名和可用参数请以当前版本文档为准。部分版本可能通过
DBMS_WORKLOAD_REPOSITORY.ASH_REPORT_TEXT输出纯文本格式,ASH_REPORT_HTML输出 HTML 格式。
四、ASH 报告如何读?——核心分析框架
4.1 概要信息
报告开头的概要信息是快速判断问题规模的入口:
Analysis Period: 08:30:00 ~ 12:00:00
Duration: 3.5 hours
Total Samples: 12,600
Active Sessions (avg): 4.2
Active Sessions (max): 287
SQLs Sampled: 185
快速判断逻辑:
-
Active Sessions (avg) 远低于 (max) → 存在突发尖峰,不是持续性负载 -
总采样数 / 总时长 = 平均活跃会话数(反映系统整体繁忙程度) -
如 12600 / 12600 秒 = 1.0 → 平均每秒1个活跃会话,负载不重 -
如 12600 / 3600 秒 = 3.5 → 平均3.5个活跃会话持续在忙
4.2 Top 等待事件分析
这是 ASH 报告中最重要的部分。等待事件告诉你"系统把时间花在了哪里"。
Top Wait Events:
┌──────────────────────┬─────────┬──────┐
│ Event Name │ Count │ % │
├──────────────────────┼─────────┼──────┤
│ disk read │ 4,800 │ 38.1%│ ← IO 瓶颈
│ latch: session │ 3,200 │ 25.4%│ ← 锁竞争
│ CPU + Wait for CPU │ 2,500 │ 19.8%│ ← CPU 密集
│ enqueue lock │ 1,100 │ 8.7%│ ← 行锁
│ network send │ 500 │ 4.0%│ ← 网络传输
└──────────────────────┴─────────┴──────┘
OceanBase 常见等待事件解读:
|
|
|
|
|
|---|---|---|---|
disk read
db file sequential read
|
|
|
|
CPU + Wait for CPU |
|
|
|
latch: xxx |
|
|
|
enqueue lock |
|
|
|
row lock wait |
|
|
__all_trans
|
io read
io write
|
|
|
|
sleep |
|
|
large_query_threshold
|
rpc in
rpc out
|
|
|
|
net read
net write
|
|
|
|
等待分类(Wait Class)
OceanBase 的等待事件可归为以下几类:
CPU → 正在 CPU 上执行或等待 CPU 调度
System IO → 系统级 IO(如合并、转储)
User IO → 用户 SQL 触发的 IO(如读取数据块)
Concurrency → 并发控制(锁、Latch)
Network → 网络通信
Other → 其他(如 sleep、idle)
4.3 Top SQL 分析
ASH 报告中的 Top SQL 按被采样到的次数排序,采样次数越多说明该 SQL 占用的执行时间越长。
Top SQL:
┌──────────────────────────┬────────┬──────┬─────────────────┐
│ SQL_ID │ Samples│ % │ Top Wait Event │
├──────────────────────────┼────────┼──────┼─────────────────┤
│ A1A6369F225E... │ 4,200 │ 33.3%│ disk read (76%) │
│ B2C7389F... │ 2,800 │ 22.2%│ latch (89%) │
│ C3D841A0... │ 1,500 │ 11.9%│ CPU (92%) │
└──────────────────────────┴────────┴──────┴─────────────────┘
分析要点:
-
采样次数 × 采样间隔 ≈ 总耗时(如 4200 次 × 1秒 = ~70 分钟) -
Top Wait Event 告诉你这条 SQL 的时间花在哪——是 IO、CPU 还是锁 -
占比 > 20% 的 SQL 通常是优化的首要目标 -
结合 SQL_ID去 SQL Audit 查看完整执行计划和统计信息
4.4 时间分布分析
ASH 报告中的时间分布图帮助你判断问题是持续性的还是突发的。
Active Sessions Over Time:
08:30 ████████░░░░░░░░░░░░ 2.1 avg
09:00 ████████████░░░░░░░░ 3.5 avg
09:30 ████████████████████ 8.0 avg ← 开始飙高
10:00 ██████████████████████████████████ 12.5 avg ← 峰值
10:30 ██████████████████████████████ 10.2 avg
11:00 ████████████████░░░░ 6.8 avg
11:30 ████████░░░░░░░░░░░░ 2.5 avg ← 逐渐恢复
12:00 ████░░░░░░░░░░░░░░░░ 1.2 avg
判断逻辑:
-
持续高位:稳态负载过高,需要扩容或优化慢 SQL -
尖峰跳变:突发事件(如计划跳变、批量任务启动、故障触发) -
周期性波动:定时任务、定时合并、周期性业务高峰
五、典型诊断场景
场景一:时间段内系统变慢,不知道哪条 SQL 导致
步骤:
-- 1. 生成 ASH 报告,覆盖变慢的时间段
CALL DBMS_WORKLOAD_REPOSITORY.ASH_REPORT('2026-07-23 09:30:00', '2026-07-23 11:00:00');
-- 2. 从报告中找到 Top SQL 的 SQL_ID
-- 3. 查看 Top SQL 的完整文本和执行计划
SELECT sql_id, query_sql, plan_id
FROM gv$ob_sql_audit
WHERE sql_id = 'sql_id'
LIMIT1;
-- 4. 查看该 SQL 在此时间段的等待事件分布
SELECT event_name, wait_class, COUNT(*) AS cnt
FROM gv$active_session_history
WHERE sql_id = 'sql_id'
AND sample_time BETWEEN'2026-07-23 09:30:00'AND'2026-07-23 11:00:00'
GROUPBY event_name, wait_class
ORDERBY cnt DESC;
-- 5. 根据等待事件类型采取对应优化措施
场景二:CPU 突然飙高,疑似计划跳变
-- 1. 查看 CPU 采样占比变化
SELECT TO_CHAR(sample_time, 'HH24:MI') AS time_bucket,
COUNT(*) AS total,
SUM(CASEWHEN wait_class = 'CPU'THEN1ELSE0END) AS cpu_cnt,
ROUND(SUM(CASEWHEN wait_class = 'CPU'THEN1ELSE0END) * 100.0 / COUNT(*), 1) AS cpu_pct
FROM gv$active_session_history
WHERE sample_time >= '2026-07-23 09:00:00'
AND sample_time = NOW() - INTERVAL 2 HOUR
GROUP BY time_bucket, wait_class
ORDER BY time_bucket, samples DESC;
6.2 会话活跃度对比
-- 对比高峰期 vs 低峰期的活跃会话画像
SELECT
CASE
WHEN sample_time BETWEEN'2026-07-23 10:00:00'AND'2026-07-23 11:00:00'
THEN'PEAK'
ELSE'NORMAL'
ENDASperiod,
wait_class,
COUNT(*) AS samples,
ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(PARTITIONBY
CASE
WHEN sample_time BETWEEN'2026-07-23 10:00:00'AND'2026-07-23 11:00:00'
THEN'PEAK'
ELSE'NORMAL'
END), 1) AS pct
FROM gv$active_session_history
WHERE sample_time BETWEEN'2026-07-23 09:00:00'AND'2026-07-23 12:00:00'
GROUPBYperiod, wait_class
ORDERBYperiod, samples DESC;
6.3 SQL 级别的时间模型
-- 为特定 SQL 构建 "时间模型"
SELECT
sql_id,
event_name,
COUNT(*) AS samples,
ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(PARTITIONBY sql_id), 1) AS pct_of_sql,
SUM(COUNT(*)) OVER(PARTITIONBY sql_id) AS total_samples
FROM gv$active_session_history
WHERE sql_id IN (
SELECT sql_id
FROM gv$active_session_history
WHERE sample_time >= NOW() - INTERVAL 1 HOUR
GROUP BY sql_id
ORDER BY COUNT(*) DESC
LIMIT 5
)
AND sample_time >= NOW() - INTERVAL 1 HOUR
GROUP BY sql_id, event_name
ORDER BY sql_id, samples DESC;
七、注意事项与最佳实践
7.1 ASH 数据的局限性
|
|
|
|
|---|---|---|
| 采样误差 |
|
|
| 概率性 |
|
|
| 内存限制 |
|
|
| 权限要求 |
|
GV$ACTIVE_SESSION_HISTORY 的权限
|
7.2 最佳实践
1. 发现问题后第一时间保留 ASH 数据:
-- 问题发生时立即导出 ASH 报告
CALL DBMS_WORKLOAD_REPOSITORY.ASH_REPORT(
'2026-07-23 08:30:00',
'2026-07-23 12:00:00'
);
2. 结合 SQL Audit 做联动分析:
-- 从 ASH 找到 Top SQL_ID → 去 SQL Audit 查详细计划
SELECT sql_id, query_sql, elapsed_time, executions, plan_id
FROM gv$ob_sql_audit
WHERE sql_id = '从ASH获取的SQL_ID'
ORDER BY request_time DESC
LIMIT 10;
3. 结合 observer 日志做深度排查:
-
ASH 定位时间段 + Top SQL_ID + Top Wait Event -
SQL Audit 查看执行计划 -
observer.log 查看该 SQL_ID 的详细 trace 日志 -
根因定位
4. 定期生成 AWR 快照作为基线:
-- 手动创建 AWR 快照
CALL DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT();
7.3 常见误区
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
END
瑞蓝创 OceanBase OBCP V4 精英训练营
点击下方图片立即了解详情


▼ 点击「阅读原文」,了解更多产品技术文章


