What is DBMS_PROFILER?
An interface to profile existing PL/SQL applications and identify performance bottlenecks - collecting and persistently storing granular execution data at the virtual machine level.
DBMS_PROFILER provides an interface to profile existing PL/SQL applications and identify performance bottlenecks. It lets us collect and persistently store profiler data.
The profiler gathers information at the PL/SQL virtual machine level, including the total number of times each line has been executed, the total time spent on that line, and the minimum and maximum execution times for each line.
| Table Name | Description |
|---|---|
| PLSQL_PROFILER_RUNS | Metadata per run (run ID, owner, date, comment, total time) |
| PLSQL_PROFILER_UNITS | Info per PL/SQL unit profiled (type, owner, name, total time) |
| PLSQL_PROFILER_DATA | Per-line stats (execution count, total/min/max time in nanoseconds) |
DECLARE
v_status BINARY_INTEGER;
BEGIN
v_status := DBMS_PROFILER.START_PROFILER(
run_comment => 'Benchmark Test - Batch Invoice Processing',
run_comment1 => 'Release 3.2 | ENV: UAT'
);
IF v_status != 0 THEN
DBMS_OUTPUT.PUT_LINE('START_PROFILER failed, status: ' || v_status);
END IF;
END;
/
DECLARE
v_status BINARY_INTEGER;
BEGIN
-- ... your PL/SQL code being profiled runs here ...
v_status := DBMS_PROFILER.STOP_PROFILER;
IF v_status = 0 THEN
DBMS_OUTPUT.PUT_LINE('Profiler stopped and data saved successfully.');
ELSE
DBMS_OUTPUT.PUT_LINE('STOP_PROFILER failed, status: ' || v_status);
END IF;
END;
/
DECLARE
v_status BINARY_INTEGER;
BEGIN
DBMS_PROFILER.START_PROFILER('Order Processing - Core Logic Only');
-- Profile this section
validate_order(p_order_id => 1001);
-- Pause: skip logging/audit overhead - not interested in profiling this
v_status := DBMS_PROFILER.PAUSE_PROFILER;
DBMS_OUTPUT.PUT_LINE('Paused. Status: ' || v_status);
write_audit_log(p_order_id => 1001); -- excluded from profiling
-- Resume: back to profiling the real work
v_status := DBMS_PROFILER.RESUME_PROFILER;
DBMS_OUTPUT.PUT_LINE('Resumed. Status: ' || v_status);
calculate_invoice(p_order_id => 1001);
DBMS_PROFILER.STOP_PROFILER;
END;
/
Used in conjunction with PAUSE_PROFILER. See the PAUSE_PROFILER example above for combined usage.
DECLARE
v_status BINARY_INTEGER;
BEGIN
DBMS_PROFILER.START_PROFILER('Long Batch Job');
FOR i IN 1..10000 LOOP
-- simulate work
process_order(i);
-- flush every 1000 records to free memory
IF MOD(i, 1000) = 0 THEN
v_status := DBMS_PROFILER.FLUSH_DATA;
DBMS_OUTPUT.PUT_LINE('Flushed at iteration: ' || i || ' | Status: ' || v_status);
END IF;
END LOOP;
DBMS_PROFILER.STOP_PROFILER;
END;
/
DECLARE
v_major BINARY_INTEGER;
v_minor BINARY_INTEGER;
BEGIN
DBMS_PROFILER.GET_VERSION(
major => v_major,
minor => v_minor
);
DBMS_OUTPUT.PUT_LINE('DBMS_PROFILER Version: ' || v_major || '.' || v_minor);
END;
/
DECLARE
v_status BINARY_INTEGER;
BEGIN
v_status := DBMS_PROFILER.INTERNAL_VERSION_CHECK;
IF v_status = 0 THEN
DBMS_OUTPUT.PUT_LINE('Version check passed. Package is compatible.');
ELSE
DBMS_OUTPUT.PUT_LINE('Version mismatch! Code: ' || v_status || '. Reinstall the correct DBMS_PROFILER version.');
END IF;
END;
/
SELECT
plsql_profiler_runs.RUN_DATE,
plsql_profiler_runs.RUN_COMMENT,
plsql_profiler_units.UNIT_TYPE,
plsql_profiler_units.UNIT_NAME,
plsql_profiler_data.LINE#,
plsql_profiler_data.TOTAL_OCCUR,
plsql_profiler_data.TOTAL_TIME,
plsql_profiler_data.MIN_TIME,
plsql_profiler_data.MAX_TIME,
round(plsql_profiler_data.total_time/1000000000) total_time_in_sec,
trunc(((plsql_profiler_data.total_time)/(sum(plsql_profiler_data.total_time) over()))*100,2) pct_of_time_taken
FROM
plsql_profiler_data,
plsql_profiler_runs,
plsql_profiler_units
WHERE
plsql_profiler_data.total_time > 0
AND plsql_profiler_data.runid = plsql_profiler_runs.runid
AND plsql_profiler_units.UNIT_NUMBER = plsql_profiler_data.UNIT_NUMBER
AND plsql_profiler_units.runid = plsql_profiler_runs.runid
ORDER BY
plsql_profiler_data.total_time DESC;
| Column | Source Table | Description |
|---|---|---|
| RUN_DATE | PLSQL_PROFILER_RUNS | Date and time the profiling run was started |
| RUN_COMMENT | PLSQL_PROFILER_RUNS | Comment label assigned when starting the profiler |
| UNIT_TYPE | PLSQL_PROFILER_UNITS | Type of PL/SQL unit (PROCEDURE, FUNCTION, PACKAGE BODY, etc.) |
| UNIT_NAME | PLSQL_PROFILER_UNITS | Name of the profiled PL/SQL unit |
| LINE# | PLSQL_PROFILER_DATA | Source line number within the unit |
| TOTAL_OCCUR | PLSQL_PROFILER_DATA | Total number of times the line was executed |
| TOTAL_TIME | PLSQL_PROFILER_DATA | Cumulative execution time (nanoseconds) |
| MIN_TIME | PLSQL_PROFILER_DATA | Minimum single execution time (nanoseconds) |
| MAX_TIME | PLSQL_PROFILER_DATA | Maximum single execution time (nanoseconds) |
| TOTAL_TIME_IN_SEC | Derived | Total time converted to seconds |
| PCT_OF_TIME_TAKEN | Derived | Percentage of overall profiling run time for this line |
We have a procedure slow_proc that inserts 100,000 rows into emp_log inside a loop. We want to use DBMS_PROFILER to pinpoint exactly which line consumes the most time.
CREATE OR REPLACE PROCEDURE slow_proc AS
BEGIN
FOR i IN 1..100000 LOOP
INSERT INTO emp_log VALUES (SYSDATE, i);
END LOOP;
COMMIT;
END;
/
DECLARE
v_run NUMBER;
BEGIN
DBMS_PROFILER.START_PROFILER(
run_comment => 'Testing slow_proc performance',
run_number => v_run
);
slow_proc(); -- <-- the code under test
DBMS_PROFILER.STOP_PROFILER;
DBMS_OUTPUT.PUT_LINE('Run ID: ' || v_run);
END;
/

Comments
Post a Comment