#DBMS_PROFILER
DBMS_PROFILER是Oracle兼容的PL代码性能分析工具,用于收集PL应用程序的执行性能数据,实现行级性能分析。
DBMS_PROFILER核心功能包括:
- 执行次数统计:记录每行代码的执行次数
- 执行时间测量:以纳秒为单位记录每行代码的执行时间(总时间、最小时间、最大时间)
- 代码覆盖率分析:识别哪些代码行被执行,哪些未被执行
- 性能瓶颈定位:帮助开发者快速定位耗时最长的代码段
Note:
DBMS_PROFILER高级包不适用于存算一体分布式集群部署。
执行DBMS_PROFILER高级包的用户需具备该高级包的执行权限。
使用DBMS_PROFILER的第一步是先调用CREATE_TABLES过程创建性能分析数据表。不建议自行修改表结构,以免引起不必要的报错。
性能分析会话对并行场景不生效,其收集结果将不会包含管道表函数(PIPELINED)相关数据。
对于外置自定义函数,性能分析会话仅收集其执行时间,不会收集内部执行细节。
启动性能分析会话将会对性能产生一定影响。性能分析会话期间,性能数据先在内存中累积。如果剖析时间过长或执行代码量极大,内存占用会持续增加。可通过调用FLUSH_DATA过程将数据刷入磁盘并释放内存,但这会增加I/O开销并可能影响被剖析程序的性能。
性能收集数据的生命周期为会话级,会话断开或手动调用STOP_PROFILER均可释放内存。
# CREATE_TABLES
DBMS_PROFILER.CREATE_TABLES (
force_it IN BOOLEAN DEFAULT FALSE);
该子存储过程用于创建性能分析数据表,包括PLSQL_PROFILER_RUNS、PLSQL_PROFILER_UNITS和PLSQL_PROFILER_DATA三张表。
| 参数 | 说明 |
|---|---|
| force_it | 是否强制重建。默认为FALSE,若数据表已存在则返回错误。当设置为TRUE时,若数据表已存在将先删除再重新创建。 |
示例(单机/共享集群/分布式集群部署)
-- 创建性能分析数据表
BEGIN
DBMS_PROFILER.CREATE_TABLES();
END;
/
-- 强制重建数据表
BEGIN
DBMS_PROFILER.CREATE_TABLES(force_it => TRUE);
END;
/
# START_PROFILER
DBMS_PROFILER.START_PROFILER (
run_comment IN VARCHAR := SYSDATE,
run_comment1 IN VARCHAR := '',
run_number OUT BINARY_INTEGER)
RETURN BINARY_INTEGER;
DBMS_PROFILER.START_PROFILER (
run_comment IN VARCHAR := SYSDATE,
run_comment1 IN VARCHAR := '')
RETURN BINARY_INTEGER;
DBMS_PROFILER.START_PROFILER (
run_comment IN VARCHAR := SYSDATE,
run_comment1 IN VARCHAR := '',
run_number OUT BINARY_INTEGER);
DBMS_PROFILER.START_PROFILER (
run_comment IN VARCHAR := SYSDATE,
run_comment1 IN VARCHAR := '');
该子存储函数用于启动性能分析会话,生成新的运行ID并初始化性能数据收集。返回0表示执行成功,返回1表示因参数错误而执行失败。
| 参数 | 说明 |
|---|---|
| run_comment | 运行注释,默认为当前时间戳。最大长度为2047字节。 |
| run_comment1 | 附加注释,最大长度为2047字节。可省略,默认为空字符串。 |
| run_number | 当执行成功时,设置本次运行的唯一标识符(RUNID)。 |
示例(单机/共享集群/分布式集群部署)
DECLARE
run_id BINARY_INTEGER;
ret BINARY_INTEGER;
BEGIN
ret := DBMS_PROFILER.START_PROFILER('Performance test', '', run_id);
DBMS_OUTPUT.PUT_LINE('Run ID: ' || run_id || ', Return: ' || ret);
END;
/
# STOP_PROFILER
DBMS_PROFILER.STOP_PROFILER
RETURN BINARY_INTEGER;
DBMS_PROFILER.STOP_PROFILER;
该子存储函数用于停止性能分析会话,并将内存中的性能数据写入数据库表。返回0表示执行成功,返回2表示因数据刷新失败而执行失败。
示例(单机/共享集群/分布式集群部署)
DECLARE
ret BINARY_INTEGER;
BEGIN
-- 先启动性能分析
DBMS_PROFILER.START_PROFILER('Test stop');
-- 执行待分析的代码
FOR i IN 1..100 LOOP
NULL;
END LOOP;
-- 停止性能分析
ret := DBMS_PROFILER.STOP_PROFILER();
DBMS_OUTPUT.PUT_LINE('Return: ' || ret);
END;
/
# PAUSE_PROFILER
DBMS_PROFILER.PAUSE_PROFILER
RETURN BINARY_INTEGER;
DBMS_PROFILER.PAUSE_PROFILER;
该子存储函数用于暂停性能数据收集。暂停期间执行的代码不会被记录。返回0表示执行成功。
示例(单机/共享集群/分布式集群部署)
DECLARE
ret BINARY_INTEGER;
BEGIN
-- 启动性能分析
DBMS_PROFILER.START_PROFILER('Pause test');
-- 记录初始阶段性能数据
FOR i IN 1..100 LOOP
NULL;
END LOOP;
-- 暂停性能分析
ret := DBMS_PROFILER.PAUSE_PROFILER();
DBMS_OUTPUT.PUT_LINE('Paused. Return: ' || ret);
-- 这段代码不会被记录
FOR i IN 1..1000 LOOP
NULL;
END LOOP;
-- 停止性能分析
DBMS_PROFILER.STOP_PROFILER();
END;
/
# RESUME_PROFILER
DBMS_PROFILER.RESUME_PROFILER
RETURN BINARY_INTEGER;
DBMS_PROFILER.RESUME_PROFILER;
该子存储函数用于恢复性能数据收集。返回0表示执行成功。
示例(单机/共享集群/分布式集群部署)
DECLARE
ret BINARY_INTEGER;
BEGIN
-- 启动性能分析
DBMS_PROFILER.START_PROFILER('Resume test');
-- 记录初始阶段性能数据
FOR i IN 1..100 LOOP
NULL;
END LOOP;
-- 暂停性能分析
DBMS_PROFILER.PAUSE_PROFILER();
-- 恢复性能分析
ret := DBMS_PROFILER.RESUME_PROFILER();
DBMS_OUTPUT.PUT_LINE('Resumed. Return: ' || ret);
-- 继续记录性能数据
FOR i IN 1..100 LOOP
NULL;
END LOOP;
-- 停止性能分析
DBMS_PROFILER.STOP_PROFILER();
END;
/
# FLUSH_DATA
DBMS_PROFILER.FLUSH_DATA
RETURN BINARY_INTEGER;
DBMS_PROFILER.FLUSH_DATA;
该子存储函数用于将内存中的性能数据刷新到数据库表,并释放已刷新数据的内存。返回0表示执行成功,返回2表示因数据刷新失败而执行失败。
示例(单机/共享集群/分布式集群部署)
DECLARE
ret BINARY_INTEGER;
BEGIN
-- 启动性能分析
DBMS_PROFILER.START_PROFILER('Flush test');
-- 执行长时间运行的代码
FOR outer_i IN 1..10 LOOP
FOR inner_i IN 1..10000 LOOP
NULL;
END LOOP;
-- 每轮循环后刷新数据到磁盘,释放内存
ret := DBMS_PROFILER.FLUSH_DATA();
DBMS_OUTPUT.PUT_LINE('Flushed. Return: ' || ret);
END LOOP;
-- 停止性能分析
DBMS_PROFILER.STOP_PROFILER();
END;
/
# GET_VERSION
DBMS_PROFILER.GET_VERSION (
major OUT BINARY_INTEGER,
minor OUT BINARY_INTEGER);
GET_VERSION用于获取DBMS_PROFILER包的版本信息。
| 参数 | 说明 |
|---|---|
| major | 返回主版本号,当前值为1。 |
| minor | 返回次版本号,当前值为0。 |
示例(单机/共享集群/分布式集群部署)
DECLARE
major INTEGER;
minor INTEGER;
BEGIN
DBMS_PROFILER.GET_VERSION(major, minor);
DBMS_OUTPUT.PUT_LINE('Version: ' || major || '.' || minor);
END;
/
# INTERNAL_VERSION_CHECK
DBMS_PROFILER.INTERNAL_VERSION_CHECK
RETURN BINARY_INTEGER;
该子存储函数用于内部版本兼容性检查。返回0表示执行成功。
示例(单机/共享集群/分布式集群部署)
DECLARE
ret BINARY_INTEGER;
BEGIN
ret := DBMS_PROFILER.INTERNAL_VERSION_CHECK();
DBMS_OUTPUT.PUT_LINE('Return: ' || ret);
END;
/
# 性能分析数据表
性能分析数据存储在以下三张表中:
# PLSQL_PROFILER_RUNS
存储每次性能分析的运行信息。
| 字段 | 类型 | 说明 |
|---|---|---|
| RUNID | NUMBER | 唯一运行标识符,主键。 |
| RELATED_RUN | NUMBER | 关联运行ID,当前固定为NULL。 |
| RUN_OWNER | VARCHAR2(128) | 启动运行的用户。 |
| RUN_DATE | DATE | 运行开始时间。 |
| RUN_COMMENT | VARCHAR2(2047) | 用户提供的运行注释。 |
| RUN_TOTAL_TIME | NUMBER | 运行总耗时,单位为纳秒。 |
| RUN_SYSTEM_INFO | VARCHAR2(2047) | 系统信息,当前固定为NULL。 |
| RUN_COMMENT1 | VARCHAR2(2047) | 附加注释。 |
| SPARE1 | VARCHAR2(256) | 保留字段。 |
# PLSQL_PROFILER_UNITS
存储每个库单元的性能分析信息,表中主键为(RUNID, UNIT_NUMBER)。
| 字段 | 类型 | 说明 |
|---|---|---|
| RUNID | NUMBER | 关联运行ID,外键。 |
| UNIT_NUMBER | NUMBER | 库单元内部编号,从1开始递增。 |
| UNIT_TYPE | VARCHAR2(128) | 库单元类型,包括PACKAGE SPEC、PACKAGE BODY、TYPE BODY、FUNCTION、PROCEDURE、ANONYMOUS BLOCK。 |
| UNIT_OWNER | VARCHAR2(128) | 库单元所有者。 |
| UNIT_NAME | VARCHAR2(128) | 库单元名称。 |
| UNIT_TIMESTAMP | DATE | 单元时间戳。 |
| TOTAL_TIME | NUMBER | 单元总耗时,单位为纳秒。 |
| SPARE1 | NUMBER | 保留字段,当前固定为NULL。 |
| SPARE2 | NUMBER | 保留字段,当前固定为NULL。 |
# PLSQL_PROFILER_DATA
存储每行代码的性能数据,表中主键为(RUNID, UNIT_NUMBER, LINE#)。
| 字段 | 类型 | 说明 |
|---|---|---|
| RUNID | NUMBER | 关联运行ID。 |
| UNIT_NUMBER | NUMBER | 库单元编号。 |
| LINE# | NUMBER | 源代码行号。 |
| TOTAL_OCCUR | NUMBER | 执行次数。 |
| TOTAL_TIME | NUMBER | 总执行时间,单位为纳秒。 |
| MIN_TIME | NUMBER | 最小执行时间,单位为纳秒。 |
| MAX_TIME | NUMBER | 最大执行时间,单位为纳秒。 |
| SPARE1 | NUMBER | SQL执行时间,单位为纳秒。 |
| SPARE2 | NUMBER | 保留字段,当前固定为NULL。 |
| SPARE3 | NUMBER | 保留字段,当前固定为NULL。 |
| SPARE4 | NUMBER | 保留字段,当前固定为NULL。 |
| LINE_TYPE | VARCHAR2(64) | 行类型。 |

