如何通过Oracle ASH分析数据块采样,精准定位冷热数据分布的OBJECT_ID?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1027个文字,预计阅读时间需要5分钟。
简单改写伪原创以下开头内容,不试图解释问题,不数落,不超过100字,直接输出结果:
ash 本身不直接暴露冷热数据分布,但通过 v$active_session_history 中的 current_obj# 和 current_file#/current_block#,结合对象元数据,可反推出高频访问对象(即“热”对象)——关键在采样密度与对象粒度的匹配。
为什么不能直接用 OBJECT_ID 判断冷热?
ASH 的 current_obj# 字段记录的是会话采样瞬间正在访问的对象编号,但它只在发生逻辑读、物理读、锁等待等实际访问行为时才被填充;大量空闲或仅解析 SQL 的会话不会带出该值。更重要的是:current_obj# 是运行时动态解析得到的编号,它和数据字典视图 dba_objects.object_id 对齐,但不等于 data_object_id ——后者才是段级物理标识,而热块实际落在段上。
常见错误是把 current_obj# 当成稳定 ID 直接 JOIN dba_objects 统计,却忽略了:对象重建(如 TRUNCATE 或 MOVE)后 object_id 不变但 data_object_id 变更,此时原 current_obj# 仍指向旧逻辑名,但真实 I/O 已转向新段。
如何从 ASH 样本中提取有效对象访问频次?
核心思路是:过滤出真实发生 I/O 或持有锁的样本,再按对象聚合。必须排除 session_state = 'WAITING' 且 event 为空闲事件(如 SQL*Net message from client)的记录,否则统计严重失真。
- 只保留
session_state IN ('ON CPU', 'WAITING')且event NOT LIKE 'SQL*Net%' AND event NOT LIKE 'PL/SQL%' - 强制要求
current_obj# > 0,避免系统对象(如 -1)或未解析对象干扰 - 用
MIN(sample_time)和COUNT(*)同时看“首次出现时间”和“总采样次数”,区分突发热点 vs 持续热点 - 示例语句(查最近 10 分钟):
SELECT o.object_name, o.object_type, COUNT(*) AS ash_samples, MIN(a.sample_time) AS first_seen FROM v$active_session_history a JOIN dba_objects o ON a.current_obj# = o.object_id WHERE a.sample_time > SYSDATE - 10/(24*60) AND a.current_obj# > 0 AND a.session_state IN ('ON CPU', 'WAITING') AND a.event NOT LIKE 'SQL*Net%' AND a.event NOT LIKE 'PL/SQL%' GROUP BY o.object_name, o.object_type ORDER BY ash_samples DESC;
OBJECT_ID 和 DATA_OBJECT_ID 在块级分析中怎么选?
当你要下钻到具体数据块(current_block#)是否构成热点时,必须用 data_object_id,因为块属于段(segment),不是逻辑对象。例如一个分区表,每个分区有独立段,object_id 全局唯一,但多个分区共享同一个 object_id,却各自有不同 data_object_id。
典型误操作:用 current_obj# = object_id 关联后,再查 dba_extents 定位文件/块范围——这会漏掉分区场景下的真实物理位置。
- 正确做法是先通过
dba_objects查出data_object_id,再 JOINdba_extents(条件为data_object_id = extent_data_object_id) - 若需快速验证某块是否属热点段,可用:
SELECT owner, segment_name FROM dba_extents WHERE file_id = :fno AND :blkno BETWEEN block_id AND block_id + blocks - 1 AND data_object_id = :do_id; - 注意:
v$active_session_history不存data_object_id,必须靠current_obj# → object_id → data_object_id二级映射
采样偏差会导致哪些误判?
ASH 是每秒一次的随机采样,不是全量 trace。这意味着:短生命周期 SQL(
最容易被忽略的一点:ASH 缓冲区大小受 _ash_size 隐含参数控制,默认约 5MB,高负载实例可能 30 秒前的数据就被覆盖。所以“查不到历史热块”不等于没发生过,可能只是缓冲区已滚动刷新。
本文共计1027个文字,预计阅读时间需要5分钟。
简单改写伪原创以下开头内容,不试图解释问题,不数落,不超过100字,直接输出结果:
ash 本身不直接暴露冷热数据分布,但通过 v$active_session_history 中的 current_obj# 和 current_file#/current_block#,结合对象元数据,可反推出高频访问对象(即“热”对象)——关键在采样密度与对象粒度的匹配。
为什么不能直接用 OBJECT_ID 判断冷热?
ASH 的 current_obj# 字段记录的是会话采样瞬间正在访问的对象编号,但它只在发生逻辑读、物理读、锁等待等实际访问行为时才被填充;大量空闲或仅解析 SQL 的会话不会带出该值。更重要的是:current_obj# 是运行时动态解析得到的编号,它和数据字典视图 dba_objects.object_id 对齐,但不等于 data_object_id ——后者才是段级物理标识,而热块实际落在段上。
常见错误是把 current_obj# 当成稳定 ID 直接 JOIN dba_objects 统计,却忽略了:对象重建(如 TRUNCATE 或 MOVE)后 object_id 不变但 data_object_id 变更,此时原 current_obj# 仍指向旧逻辑名,但真实 I/O 已转向新段。
如何从 ASH 样本中提取有效对象访问频次?
核心思路是:过滤出真实发生 I/O 或持有锁的样本,再按对象聚合。必须排除 session_state = 'WAITING' 且 event 为空闲事件(如 SQL*Net message from client)的记录,否则统计严重失真。
- 只保留
session_state IN ('ON CPU', 'WAITING')且event NOT LIKE 'SQL*Net%' AND event NOT LIKE 'PL/SQL%' - 强制要求
current_obj# > 0,避免系统对象(如 -1)或未解析对象干扰 - 用
MIN(sample_time)和COUNT(*)同时看“首次出现时间”和“总采样次数”,区分突发热点 vs 持续热点 - 示例语句(查最近 10 分钟):
SELECT o.object_name, o.object_type, COUNT(*) AS ash_samples, MIN(a.sample_time) AS first_seen FROM v$active_session_history a JOIN dba_objects o ON a.current_obj# = o.object_id WHERE a.sample_time > SYSDATE - 10/(24*60) AND a.current_obj# > 0 AND a.session_state IN ('ON CPU', 'WAITING') AND a.event NOT LIKE 'SQL*Net%' AND a.event NOT LIKE 'PL/SQL%' GROUP BY o.object_name, o.object_type ORDER BY ash_samples DESC;
OBJECT_ID 和 DATA_OBJECT_ID 在块级分析中怎么选?
当你要下钻到具体数据块(current_block#)是否构成热点时,必须用 data_object_id,因为块属于段(segment),不是逻辑对象。例如一个分区表,每个分区有独立段,object_id 全局唯一,但多个分区共享同一个 object_id,却各自有不同 data_object_id。
典型误操作:用 current_obj# = object_id 关联后,再查 dba_extents 定位文件/块范围——这会漏掉分区场景下的真实物理位置。
- 正确做法是先通过
dba_objects查出data_object_id,再 JOINdba_extents(条件为data_object_id = extent_data_object_id) - 若需快速验证某块是否属热点段,可用:
SELECT owner, segment_name FROM dba_extents WHERE file_id = :fno AND :blkno BETWEEN block_id AND block_id + blocks - 1 AND data_object_id = :do_id; - 注意:
v$active_session_history不存data_object_id,必须靠current_obj# → object_id → data_object_id二级映射
采样偏差会导致哪些误判?
ASH 是每秒一次的随机采样,不是全量 trace。这意味着:短生命周期 SQL(
最容易被忽略的一点:ASH 缓冲区大小受 _ash_size 隐含参数控制,默认约 5MB,高负载实例可能 30 秒前的数据就被覆盖。所以“查不到历史热块”不等于没发生过,可能只是缓冲区已滚动刷新。

