
好的,我们来对 Oracle 19C 数据库中的 V$TOPLEVELCALL 动态性能视图进行详尽、深入的解析。这是一个用于高级性能诊断、特别是理解 SQL 执行调用层次结构的关键视图。
1. 作用与概述
V$TOPLEVELCALL 视图用于跟踪和统计由最外层(顶级)用户调用所引发的数据库内部调用(递归SQL执行)的性能数据。
- 核心概念 - “顶级调用”(Top-Level Call): 指直接由客户端应用程序发起的 SQL 语句或 PL/SQL 调用。例如,一个 Java 应用程序执行的
SELECT * FROM employees。 - 核心概念 - “递归调用”(Recursive Call): 指为了完成“顶级调用”而由数据库内部自动执行的 SQL 语句。例如,执行上述
SELECT时,如果数据缓冲区没有所需数据,Oracle 需要执行递归调用(递归SQL)从磁盘读取数据块到内存。此外,数据字典查询、空间分配(ALTER TABLE分配区间)、PL/SQL 中的 SQL、触发器中的 SQL 等都可能是递归调用。 - 视图目的: 此视图将递归调用的资源消耗(CPU、等待时间、物理读等)归属到其根源的顶级调用上。它回答了“这个复杂的用户操作(顶级调用),到底在数据库内部引发了哪些工作(递归调用),各自消耗了多少资源?”的问题。
2. 使用场景
此视图主要用于高级性能诊断和深度资源消耗分析:
-
诊断由递归SQL引起的性能问题:
- 当一个用户操作(如一个简单的
INSERT)执行得很慢,但V$SQL显示该语句本身消耗资源很少时,问题很可能出在递归SQL上。通过此视图可以定位到是哪个顶级调用导致了大量的递归执行,并量化其影响。
- 当一个用户操作(如一个简单的
-
分析DDL操作的真实开销:
CREATE INDEX,ALTER TABLE MOVE等 DDL 命令会在内部执行大量递归SQL(查询数据字典、分配和初始化空间、构建索引结构等)。此视图可以揭示这些操作内部各个阶段(如空间管理调用)的详细开销。
-
理解PL/SQL执行的细节:
- 执行一个存储过程(顶级调用)会触发过程内部多条SQL语句的执行(递归调用)。此视图可以帮助分析过程的总开销在内部SQL上的分布。
-
全局资源审计:
- 更准确地评估一个应用程序操作(顶级调用)的总成本,包括其所有“隐藏”的递归成本。
3. 字段含义详解
V$TOPLEVELCALL 视图的字段围绕顶级调用ID和聚合的递归调用统计信息。
| 字段名称 | 数据类型 | 含义说明 |
|---|---|---|
| TOP_LEVEL_CALL_ID | NUMBER | 顶级调用的唯一标识符。这是整个调用树的根ID。在 V$SQL 和 V$SESSION 等视图中,SQL 的 TOP_LEVEL_CALL_ID 字段指向此ID。 |
| TOP_LEVEL_CALL_NAME | VARCHAR2(64) | 顶级调用的名称或类型。常见值: • PL/SQL EXECUTE • SELECT • INSERT • UPDATE • DELETE • CREATE INDEX (及其他DDL) • UNKNOWN |
| CALL_TYPE | VARCHAR2(10) | 调用类型的简写。通常是 RECURSIVE,因为此视图主要统计递归调用。 |
| CALL_CLASS | VARCHAR2(18) | 调用的类别,提供了更细粒度的分类。例如: • RECURSIVE SPACE MGMT (空间管理递归SQL) • RECURSIVE SQL (一般的递归SQL) • PL/SQL |
| CPU_TIME | NUMBER | 归属于此顶级调用的所有递归调用所消耗的总CPU时间(单位:微秒)。 |
| ELAPSED_TIME | NUMBER | 归属于此顶级调用的所有递归调用所消耗的总时间(包括等待时间,单位:微秒)。 |
| BUFFER_GETS | NUMBER | 归属于此顶级调用的所有递归调用所执行的总逻辑读次数。 |
| DISK_READS | NUMBER | 归属于此顶级调用的所有递归调用所执行的总物理读次数。 |
| DIRECT_WRITES | NUMBER | 归属于此顶级调用的所有递归调用所执行的总直接路径写次数(例如,直接路径加载,LOB操作)。 |
| ROWS_PROCESSED | NUMBER | 归属于此顶级调用的所有递归调用所处理的总行数。 |
| COUNT | NUMBER | 归属于此顶级调用的递归调用发生的总次数。 |
| CON_ID | NUMBER | 所属容器的ID。在多租户环境中,标识该统计信息属于哪个PDB或CDB$ROOT。 |
4. 相关视图与基表
-
相关动态性能视图:
V$SQL: 这是最重要的关联视图。V$SQL中的TOP_LEVEL_CALL_ID字段指向V$TOPLEVELCALL.TOP_LEVEL_CALL_ID,从而可以将一条递归SQL语句与其根源的顶级调用关联起来。V$SQL中的CALL_CLASS字段也与本视图的CALL_CLASS对应。V$SESSION: 当前会话正在执行的操作也有TOP_LEVEL_CALL_ID,可用于实时诊断。V$ACTIVE_SESSION_HISTORY(ASH) /DBA_HIST_ACTIVE_SESS_HISTORY: ASH数据中也包含TOP_LEVEL_CALL_ID,允许对历史活动进行基于调用层次的分析。V$SQLSTATS: 提供SQL的聚合统计,也包含TOP_LEVEL_CALL_ID。
-
基表(Underlying Base Table):
- **XKGLTOP∗∗:这是‘VKGLTOP**: 这是 `VKGLTOP∗∗:这是‘VTOPLEVELCALL` 所依赖的底层内存结构(基表)。它存储了顶级调用相关的统计信息。与其他X$表一样,它是内部的、未公开的,严禁直接查询。
- **XKGLCALLTREE∗∗:另一个相关的XKGLCALLTREE**: 另一个相关的XKGLCALLTREE∗∗:另一个相关的X表,可能用于维护调用树结构。
- 视图定义查询:
SELECT view_definition FROM v$fixed_view_definition WHERE view_name = 'GV$TOPLEVELCALL';
5. 底层详细原理
-
调用树(Call Tree)的构建:
- 当一个顶级调用(如
SELECT ...)进入数据库时,Oracle 会为其分配一个唯一的TOP_LEVEL_CALL_ID。 - 在执行过程中,如果该调用需要触发递归SQL(例如,由于硬解析需要查询数据字典
SYS.TAB$),数据库内核会记录下这些递归SQL,并将它们的执行归属到同一个TOP_LEVEL_CALL_ID下。 - 这样就形成了一棵以用户SQL为根、以各种递归SQL为枝叶的调用树。
- 当一个顶级调用(如
-
统计信息的聚合:
- 递归SQL在执行时,其资源消耗(CPU、I/O、逻辑读等)不仅会被记录到该递归SQL本身的游标中(在
V$SQL中),还会被聚合到其所属的TOP_LEVEL_CALL_ID对应的统计记录中。 V$TOPLEVELCALL视图本质上就是这些聚合后的统计信息的展示。它按TOP_LEVEL_CALL_ID和CALL_CLASS分组,累加所有归属过来的递归调用的资源使用情况。
- 递归SQL在执行时,其资源消耗(CPU、I/O、逻辑读等)不仅会被记录到该递归SQL本身的游标中(在
-
数据生命周期与开销:
- 这些统计信息存储在SGA中,实例重启后会被重置。
- 维护调用树和聚合统计信息会带来轻微的性能开销。因此,在某些极端性能敏感的场景下,Oracle可能不会对非常短暂或简单的调用进行深度跟踪。
6. 相关知识点介绍
-
递归SQL的常见来源:
- 数据字典操作: 硬解析时查询表、列、权限等信息。
- 空间管理: 执行DML时分配新区间(
ALTER TABLE ... ALLOCATE EXTENT)、管理位图段。 - 触发器: 触发器内部定义的SQL代码。
- PL/SQL: 存储过程、函数、包中执行的SQL。
- 索引维护:
CREATE INDEX时排序和构建结构。 - 审计: 如果启用了审计,写审计记录。
- 高级功能: 如递归WITH查询(CTE)、某些分区操作等。
-
CALL_CLASS的含义:RECURSIVE SPACE MGMT: 与段空间管理相关的递归调用,是性能问题的常见来源,特别是当表有很多扩展或使用ASSM管理时。RECURSIVE SQL: 一般的递归SQL。PL/SQL: 与PL/SQL引擎执行相关的调用。
-
与等待事件的关系: 递归调用产生的等待事件(如
db file sequential read)也会被归属到顶级调用。在ASH报告中,可以按TOP_LEVEL_CALL_ID进行筛选,查看该调用树内发生的所有等待事件。
7. 常用查询 SQL
1. 查找消耗最多递归资源(如物理读)的顶级调用
这是最核心的查询,用于发现“隐藏”的性能消耗源。
SELECT top_level_call_id,
top_level_call_name,
call_class,
disk_reads,
round(cpu_time / 1000000, 2) as cpu_secs, -- 将微秒转换为秒
round(elapsed_time / 1000000, 2) as elapsed_secs,
buffer_gets,
count
FROM v$toplevelcall
WHERE disk_reads > 0 OR cpu_time > 0 -- 筛选有活动的调用
ORDER BY disk_reads DESC; -- 按物理读排序,也可以按cpu_time或buffer_gets排序
2. 关联 V$SQL,查找导致大量递归调用的具体SQL文本
此查询将顶级调用ID与SQL文本关联起来。
SELECT t.top_level_call_id,
t.top_level_call_name,
t.call_class,
s.sql_text,
t.disk_reads,
t.buffer_gets
FROM v$toplevelcall t
JOIN v$sql s ON t.top_level_call_id = s.top_level_call_id
WHERE s.top_level_call_id IS NOT NULL
AND t.disk_reads > 1000 -- 示例阈值
ORDER BY t.disk_reads DESC;
3. 分析特定SQL语句的递归调用明细
如果已知一个SQL的 SQL_ID,想查看它引发的递归调用详情。
SELECT s.sql_id,
s.sql_text as recursive_sql_text,
s.executions as recursive_execs,
t.top_level_call_id,
t.disk_reads,
t.buffer_gets
FROM v$sql s
JOIN v$toplevelcall t ON s.top_level_call_id = t.top_level_call_id
WHERE s.sql_id = '&your_sql_id'; -- 替换为你要分析的SQL_ID
4. 按调用类型(CALL_CLASS)分组,查看系统总体递归开销
SELECT call_class,
SUM(disk_reads) AS total_disk_reads,
SUM(buffer_gets) AS total_buffer_gets,
ROUND(SUM(cpu_time) / 1000000, 2) AS total_cpu_secs,
SUM(count) AS total_recursive_calls
FROM v$toplevelcall
GROUP BY call_class
ORDER BY total_disk_reads DESC;
5. 在ASH数据中分析历史顶级调用(需要Diagnostic Pack)
SELECT h.top_level_call_id,
t.top_level_call_name,
t.call_class,
COUNT(*) AS ash_sample_count,
ROUND(COUNT(*) * 10 / 60, 2) AS approx_mins -- 假设ASH每10秒采样一次
FROM dba_hist_active_sess_history h
JOIN v$toplevelcall t ON h.top_level_call_id = t.top_level_call_id
WHERE h.sample_time > SYSDATE - 1/24 -- 查询最近1小时
AND h.top_level_call_id IS NOT NULL
GROUP BY h.top_level_call_id, t.top_level_call_name, t.call_class
ORDER BY ash_sample_count DESC;
总结
V$TOPLEVELCALL 动态性能视图提供了穿透表面,洞察根源的能力。它将数据库内部复杂的、自动执行的递归操作与最终的用户请求清晰地关联起来。
通过此视图,您可以:
- 量化 一个用户操作的真实、总体的资源消耗,包括其所有“幕后”工作。
- 定位 那些表面看起来简单、但实际上引发了大量内部活动的性能瓶颈语句。
- 剖析 DDL、空间分配等操作的内部成本构成。
- 深化 对Oracle数据库内部运作机制的理解。
它是性能优化专家工具箱中一件强大的武器,尤其适用于解决那些“简单SQL却执行缓慢”的疑难杂症。将它与 V$SQL、ASH 等视图结合使用,可以构建出极其强大的端到端性能诊断工作流。
欢迎关注我的公众号《IT小Chen》

被折叠的 条评论
为什么被折叠?



