基于湖库一体架构,统一管理结构化、半结构化与非结构化等多模态数据,一个系统承载事务处理、实时分析与 AI 工作负载。
说明
由于当前 USER_SOURCE 表中存储的过程源码信息只有一行,在执行完 DBMS_PROFILER 分析后,数据与存储过程源码关联需要一个代理表。在 V4.4.2 版本,将会提供 USER_SOURCE 表,该表提供按照行拆分的 USER_SOURCE 视图,DBMS_PROFILER 后的数据可以与 USER_SOURCE 关联到具体的行。
更新时间:2026-07-28
在 AP(Analytical Processing)场景下,存储过程的稳定性和性能是业务能否落地的关键。在实际的业务实践中,业务更关注存储过程的性能,比如每日的跑批是否能在合理的时间内完成结算是业务更关注的指标。
在 PL/SQL 开发过程中,性能分析是确保系统高效运行的关键环节。在 OceanBase 数据库 V4.2.3 之前,PL/SQL 性能问题定位手段有限,主要依靠 GV$OB_SQL_AUDIT 视图分析 PL 和内部 SQL 的执行时间差异,但是无法获取语法块(WHILE 和 FOR 等)和语句级别的详细执行时间。在跑批场景中,循环语句频繁执行相同 SQL 语句,当触发 SQL Audit 视图淘汰机制时,无法记录完整的执行时间信息,影响性能问题定位。因此,在 OceanBase 数据库 V4.2.3 版本引入了 DBMS_PROFILER,提供行级耗时性能定位功能,兼容 Oracle 的 PL 行级别的性能分析工具,可以抓取一个 PL 请求中行级别的执行热点信息。
SQL Audit 提供了多个 PL 相关的重要字段用于性能分析:
| 字段名 | 数据类型 | 说明 |
|---|---|---|
| REQUEST_TYPE | NUMBER(38) | 请求类型,request_type = 11 代表来自 PL 的 SQL 语句 |
| PL_TRACE_ID | VARCHAR2(128) | PL 跟踪 ID,用于关联 PL 和其内部 SQL 语句 |
| PLSQL_EXEC_TIME | NUMBER(38) | 纯 PL 执行时间(扣除 SQL 执行时间) |
| PLSQL_COMPILE_TIME | NUMBER(38) | PL 编译时间 |
您可以通过 REQUEST_TYPE 判断当前请求是否来自 PL。REQUEST_TYPE = 11 代表来自 PL 的 SQL 语句。当您查询 GV$OB_SQL_AUDIT 视图时,可以通过 REQUEST_TYPE = 11 来筛选出所有来自 PL/SQL 的 SQL 语句。
从 V4.2.2 版本引入,PL_TRACE_ID 将 PL 与 PL 中 SQL 语句的执行切分开。一个请求中 PL 的执行是一个统一的顶层 PL_TRACE_ID,PL 中的每个 SQL 则有独立的 TRACE_ID。当您查询 GV$OB_SQL_AUDIT 视图时,可以通过 PL_TRACE_ID 来关联 PL 请求中所有 SQL 语句。
在 V4.2.2 之后,当您查询 GV$OB_SQL_AUDIT 视图时,需要通过 PL_TRACE_ID 来关联 PL 请求中所有 SQL 语句。示例如下:
-- 示例:查看 PL 执行详情
CREATE TABLE t (id INT, name VARCHAR(50));
CREATE OR REPLACE PROCEDURE p IS
x INT;
BEGIN
SELECT COUNT(*) INTO x FROM t;
END;
/
CALL p();
SELECT query_sql, trace_id, pl_trace_id, plsql_exec_time, plsql_compile_time, request_type
FROM gv$ob_sql_audit
WHERE pl_trace_id = last_trace_id();
输出示例:
+----------------------------------------------+-----------------------------------+-----------------------------------+-----------------+--------------------+--------------+
| QUERY_SQL | TRACE_ID | PL_TRACE_ID | PLSQL_EXEC_TIME | PLSQL_COMPILE_TIME | REQUEST_TYPE |
+----------------------------------------------+-----------------------------------+-----------------------------------+-----------------+--------------------+--------------+
| select count(*) AS "COUNT(*)" from "SYS"."T" | YB42AC1E87C6-00063EDCF3A608A6-0-0 | YB42AC1E87C6-00063ECE9A6608E3-0-0 | 0 | 0 | 11 |
| CALL p() | YB42AC1E87C6-00063ECE9A6608E3-0-0 | YB42AC1E87C6-00063ECE9A6608E3-0-0 | 297 | 14484 | 2 |
+----------------------------------------------+-----------------------------------+-----------------------------------+-----------------+--------------------+--------------+
从 V4.2.2 版本引入,PLSQL_EXEC_TIME 记录了当前请求中纯 PL 执行的时间,即扣除 SQL 执行时间剩余的时间。您可以通过该字段判断当前的 PL 请求本身是否为性能瓶颈。
记录当前请求中因为 PL 编译所花费的时间。在一个稳定系统中,频繁编译会导致严重的性能问题,因此如果系统中该时间频繁出现,则需要关注是否有编译问题。
为了能更细节地分析 PL 执行过程的详细耗时,在 V4.2.3 版本引入了 DBMS_PROFILER 包。DBMS_PROFILER 是兼容 Oracle 的 PL 行级别的性能分析工具,可以抓取一个 PL 请求中行级别的执行热点信息。
由于当前 USER_SOURCE 表中存储的过程源码信息只有一行,在执行完 DBMS_PROFILER 分析后,数据与存储过程源码关联需要一个代理表。在 V4.4.2 版本,将会提供 USER_SOURCE 表,该表提供按照行拆分的 USER_SOURCE 视图,DBMS_PROFILER 后的数据可以与 USER_SOURCE 关联到具体的行。
-- 启动性能分析
CALL DBMS_PROFILER.start_profiler(run_comment => 'test' || SYSDATE);
CREATE TABLE t (id INT, name VARCHAR(50));
-- 创建测试存储过程
CREATE OR REPLACE PROCEDURE p2 IS
x INT;
BEGIN
FOR idx IN 1..10000 LOOP
BEGIN
x := idx + 1;
INSERT INTO t VALUES(x, 'test' || x);
END;
END LOOP;
END;
/
-- 执行存储过程
CALL p2();
-- 停止性能分析
CALL DBMS_PROFILER.stop_profiler();
-- 查看性能分析结果
SELECT * FROM plsql_profiler_runs;
输出示例:
+-------+-------------+-----------+-----------+---------------+----------------+-----------------+--------------+--------+
| RUNID | RELATED_RUN | RUN_OWNER | RUN_DATE | RUN_COMMENT | RUN_TOTAL_TIME | RUN_SYSTEM_INFO | RUN_COMMENT1 | SPARE1 |
+-------+-------------+-----------+-----------+---------------+----------------+-----------------+--------------+--------+
| 1 | NULL | SYS | 23-SEP-25 | test23-SEP-25 | 667000000000 | NULL | NULL | NULL |
+-------+-------------+-----------+-----------+---------------+----------------+-----------------+--------------+--------+
-- 查看执行单元
SELECT * FROM plsql_profiler_units WHERE runid=1;
输出示例:
+-------+-------------+--------------+------------+---------------+----------------+------------+--------+--------+
| RUNID | UNIT_NUMBER | UNIT_TYPE | UNIT_OWNER | UNIT_NAME | UNIT_TIMESTAMP | TOTAL_TIME | SPARE1 | SPARE2 |
+-------+-------------+--------------+------------+---------------+----------------+------------+--------+--------+
| 1 | 311114 | PACKAGE BODY | SYS | DBMS_PROFILER | 15-SEP-25 | 0 | NULL | NULL |
| 1 | 500002 | PROCEDURE | SYS | P | 22-SEP-25 | 0 | NULL | NULL |
| 1 | 500019 | PROCEDURE | SYS | P2 | 23-SEP-25 | 0 | NULL | NULL |
+-------+-------------+--------------+------------+---------------+----------------+------------+--------+--------+
-- 查看行级性能数据
SELECT * FROM plsql_profiler_data WHERE runid=1;
输出示例:
+-------+-------------+-------+-------------+------------+----------+----------+--------+--------+--------+--------+
| RUNID | UNIT_NUMBER | LINE# | TOTAL_OCCUR | TOTAL_TIME | MIN_TIME | MAX_TIME | SPARE1 | SPARE2 | SPARE3 | SPARE4 |
+-------+-------------+-------+-------------+------------+----------+----------+--------+--------+--------+--------+
| 1 | 311095 | 1 | 2 | 7945 | 2016 | 5929 | NULL | NULL | NULL | NULL |
| 1 | 311095 | 18 | 2 | 611 | 278 | 333 | NULL | NULL | NULL | NULL |
| 1 | 311095 | 21 | 2 | 82814 | 26726 | 56088 | NULL | NULL | NULL | NULL |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
+-------+-------------+-------+-------------+------------+----------+----------+--------+--------+--------+--------+
有些业务场景需要统计一段时间内的存储过程耗时开销,这里推荐使用 Oracle 兼容的方式。通过系统触发器的方式,在每次会话登录的 LogOn 触发器上 StartProfiler,在 LogOff 触发器上 StopProfiler。
系统触发器在 V4.2.5.bp1 开始支持。
-- 创建登录触发器
CREATE OR REPLACE TRIGGER after_logon_trg
AFTER LOGON ON DATABASE
WHEN (ora_login_user() IN ('TEST'))
BEGIN
dbms_profiler.start_profiler();
END;
/
-- 创建登出触发器
CREATE OR REPLACE TRIGGER before_logoff_trg
BEFORE LOGOFF ON DATABASE
WHEN (ora_login_user() IN ('TEST'))
BEGIN
dbms_profiler.stop_profiler();
END;
/
建议采用分层分析策略:
在 OceanBase 数据库中,SQL Audit 和 DBMS_PROFILER 各有优势,适用于不同的性能分析需求:
在实际应用中,可根据具体需求选择合适的工具,或结合使用,以获得更全面的性能分析结果。通过系统化的性能分析方法,能够有效识别和解决 PL/SQL 性能问题,提升系统整体运行效率。