Czy zastanawialiście się co stanie się, gdy spróbujcie profilować zawrapowany kod PL/SQL? Czy dowiemy się jakie nr linii kosztują nas najbardziej? Czy dowiemy się jakie funkcje i procedury uruchamia nas zawrapowany kod?
Jeśli tak – zapraszam do lektury 🙂
Z okazji tworzenia niniejszego wpisu utworzyłem 2 pakiety, których ciała następnie zawrapowałem:
create or replace PACKAGE PACKAGE1 AS PROCEDURE proc2_pkg(i_cnt2 NUMBER); END PACKAGE1; / CREATE OR REPLACE PACKAGE BODY PACKAGE1 AS PROCEDURE proc1_pkg(i_cnt NUMBER) IS v_last_name employees.last_name%TYPE; x number:=0; BEGIN SELECT COUNT(*) INTO x FROM EMPLOYEES; IF x = 2 THEN x := x+ 1; else -- loop FOR i IN 1..i_cnt LOOP --select SELECT last_name INTO v_last_name FROM employees WHERE employee_id = 100; END LOOP; --after loop END IF; END proc1_pkg; PROCEDURE proc2_pkg(i_cnt2 NUMBER) AS x number:=0; BEGIN -- x x:=x+1; --running proc1 proc1_pkg(i_cnt2); END proc2_pkg; END PACKAGE1; / CREATE OR REPLACE PACKAGE PACKAGE2 AS procedure proc3_pkg(i_cnt number); END PACKAGE2; / CREATE OR REPLACE PACKAGE BODY PACKAGE2 AS procedure proc3_pkg(i_cnt number) AS BEGIN PACKAGE1.proc2_pkg(200); END proc3_pkg; END PACKAGE2;
1. W celu przygotowania bazy do profilowania wykonałem (z linii poleceń):
$ cd $ORACLE_HOME/rdbms/admin $ sqlplus / as sysdba @profload.sql
2. Następnie na użytkowniku, na którym dokonywałem profilowania wykonałem zawartość pliku proftab.sql (znajduje się w tej samej lokalizacji co profload.sql). I już mamy wszystko gotowe do działania 🙂
3. Jak przeprowadzić profilowanie? Pokażę jak zrobić to używając SQL i PL/SQL. Narzędzia graficzne mogą nam dodatkowo tą pracę ułatwić 🙂
BEGIN DBMS_PROFILER.START_PROFILER(run_comment => 'commment RS'); PACKAGE2.proc3_pkg(200); DBMS_PROFILER.STOP_PROFILER; END;
run_comment pojawi się w tabeli, w której poszukamy runid profilowania:
SELECT runid, run_date, run_comment, run_total_time FROM plsql_profiler_runs ORDER BY runid;
Z powyższego zapytania bierzemy runid i wstawiamy do kolejnego zapytania:
SELECT u.runid, u.unit_number, u.unit_type, u.unit_owner, u.unit_name, d.line#, d.total_occur, d.total_time, d.min_time, d.max_time FROM plsql_profiler_units u JOIN plsql_profiler_data d ON u.runid = d.runid AND u.unit_number = d.unit_number WHERE u.runid = 1 -- <-- TUTAJ ORDER BY u.unit_number, d.line#;
Oczywiście można zamknąć to w jedno zapytanie. W przypadku, gdy nasz kod nie jest zawrapowany można wykonać join do widoków %_source w celu sprawdzenia co kryje się pod danym numerem linii.
Co zwróciło nasze zapytanie dla kodu zawrapowanego (dla celów niniejszego wpisu ograniczyłem liczbę kolumn i wierszy) ?
RUNID | UNIT_NUMBER | UNIT_TYPE | UNIT_OWNER | UNIT_NAME | LINE# | TOTAL_OCCUR | TOTAL_TIME |
---|---|---|---|---|---|---|---|
7 | 2 | PACKAGE BODY | HR | PACKAGE2 | 3 | 0 | 1030 |
7 | 2 | PACKAGE BODY | HR | PACKAGE2 | 5 | 1 | 65956 |
7 | 2 | PACKAGE BODY | HR | PACKAGE2 | 6 | 1 | 2061 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 3 | 1 | 1030 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 6 | 1 | 0 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 7 | 1 | 0 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 8 | 1 | 48090690 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 12 | 1 | 3091 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 13 | 0 | 0 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 16 | 201 | 31947 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 18 | 200 | 8832016 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 22 | 1 | 0 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 24 | 1 | 0 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 25 | 1 | 2061 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 27 | 1 | 2061 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 28 | 1 | 1030 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 29 | 1 | 0 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 31 | 1 | 2061 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 33 | 1 | 0 |
7 | 3 | PACKAGE BODY | HR | PACKAGE1 | 34 | 1 | 2061 |
Co widzimy? Jaki pakiet uruchomił się, czy dana linia wykonała się i ile czasu zajęła. Widzimy też, że w pakiecie PACKAGE1 linia (szczęśliwa) 13sta nie uruchomiła się wcale – z powodu tego, że IF nie był spełniony. Uruchomiliśmy PACKAGE2.PROC3_PKG a dowiedzieliśmy się, że został uruchomiona również procedura z PACKAGE1. Jest to o tyle istotne, że nasz kod w bazie wygląda tak:
create or replace PACKAGE BODY PACKAGE2 wrapped a000000 aa abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd b 86 a6 EhMzRB+blxBGLaqp0FEF9Ye6d64wg5m49TOf9b9cuJu/9MPnqbhfjnbWvlOOjuGs5JBMTObW ca9Whs6mIL+ycjAXnS9EnWkPSbHKLsh7RERJ6r+uJMo7pusgTVsJIDYrIJFwDt6yifWBxzV1 4NeVRIuEOwPJpqbCLs ......
Mam nadzieję, że ten wpis pomoże wszystkim zmagającym się z (oczywiście własnym 🙂 i nie tylko) zawrapowanym kodem. Testy zostały przeprowadzone na wersji 12c.
Dziękuję za lekturę! 🙂