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 let us to 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.
Run PROFTAB.SQL to create the required database tables.
Warm up the database by running the app once without profiling to avoid skewed timings.
Call START_PROFILER → execute our PL/SQL → call STOP_PROFILER.
Query the profiler tables for reports and analysis.
| 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 |
Comments
Post a Comment