I would like to measure the execution time of a stored procedure in Oracle. I have learned about the technique of writing an entry in a temporary logging table at the start and the end but am unable to use this technique.
Can you refer me to an open source/free tool with which I'm able to do this?
Thanks!
The answer depends on your environment you are using.
If you are using SQLPlus, you can enable a timer as follows :t
SQL> set timing on
Then, just execute your procedure, like :
SQL> exec my_procedure;
When the procedure will complete, a summary line will be displayed, like :
PL/SQL procedure successfully completed.
Elapsed: 00:00:03.05
From within PL/SQL, you can use dbms_utility.get_time :
DECLARE
start_time pls_integer;
BEGIN
start_time := dbms_utility.get_time;
exec my_procedure;
dbms_output.put_line((dbms_utility.get_time - start_time)/100 || ' seconds');
END;
/
Should output something like :
3 seconds
PL/SQL procedure successfully completed.
See this excellent explanation from Tom Kyte.
Execution of the stored procedure's start /end time can be logged using
DBMS_UTILITY.get_cpu_time or DBMS_UTILITY.get_time
E.g.
CREATE OR REPLACE PROCEDURE test_proc IS
BEGIN
DBMS_OUTPUT.put_line('start time '||DBMS_UTILITY.get_time);
<your statement>
DBMS_OUTPUT.put_line('end time '||DBMS_UTILITY.get_time);
END;
There are of course other ways of finding the execution time using Profiler
Have a look at this as well
If you want to get details that can actually help you diagnose issues, I highly recommend dbms_profiler.
It is easy to use and provides statistics for every line in the pl/sql including number of executions, total time, min and max.
Related
I am trying to understand complier optimizations in plsql in depth. Theoretically, default optimisation level PLSQL_OPTIMIZE_LEVEL is set to 2. To get better performance, we can set it to 3. To explain this to myself, I am using an example wherein a procedure is calling another procedure, so that the optimisation feature of level 3 (inline procedure) can be used.
Here is the first procedure:
create or replace procedure p1
is
n number:=0;
begin
for i in 1..500000000
loop
n:=n+1;
end loop;
end;
And here is the second one:
create or replace procedure CALL_PROC_ARITH
IS
BEGIN
for i in 1..10
loop
P1;
end loop;
END;
Here is the plsql_code_type for both the procedures, which is INTERPRETED.
plsql_code_type
So initially the optimisation level for both procedures is 2. And when I execute the procedure CALL_PROC_ARITH, it takes about 05:00.866 minutes.
Later, I modify the optimisation level to 3 at session level. And when I execute the procedure CALL_PROC_ARITH, it takes about 00:05:05.011 minutes which is an increase in 5 seconds.
Can someone please tell me why I see this deviation from the expected behaviour?
Will I get to see different results in case I use NATIVE compilation?
Note: I am running this from an IDE, and not directly from the SQLPlus CLI.
DB:Oracle 18c XE
You should use better sources to understand PLSQL_OPTIMIZE_LEVEL, and you should make sure you're testing the right thing the right way.
1. How does PLSQL_OPTIMIZE_LEVEL work?
The best way to learn about any parameter is with the Database Reference in the official documentation. The parameter PLSQL_OPTIMIZE_LEVEL changes frequently, so make sure you reference the precise version. There's a lot of unofficial, out-date information on the web, but here's the relevant text for 18c:
0
Maintains the evaluation order and hence the pattern of side effects,
exceptions, and package initializations of Oracle9i and earlier
releases. Also removes the new semantic identity of BINARY_INTEGER and
PLS_INTEGER and restores the earlier rules for the evaluation of
integer expressions. Although code will run somewhat faster than it
did in Oracle9i, use of level 0 will forfeit most of the performance
gains of PL/SQL in Oracle Database 10g.
1
Applies a wide range of optimizations to PL/SQL programs including the
elimination of unnecessary computations and exceptions, but generally
does not move source code out of its original source order.
2
Applies a wide range of modern optimization techniques beyond those of
level 1 including changes which may move source code relatively far
from its original location.
3
Applies a wide range of optimization techniques beyond those of level
2, automatically including techniques not specifically requested.
That description makes it hard to tell when inlining will occur. It sounds like inlining might occur at level 1 and will likely occur at level 2. My tests below show a large inlining performance difference from 0 to 1, a very tiny difference from 1 to 2, and no difference from 2 to 3.
But a lot of the behavior is undocumented so it's hard to tell which optimization will happen when.
2. Are you recompiling the code after setting the level?
Merely setting the session value is not enough, you must also recompile the procedures, like this:
alter session set plsql_optimize_level=3;
alter procedure call_proc_arith compile;
alter procedure p1 compile;
3. Are you really testing inlining?
Your procedures contain a lot of looping and a procedure call, but I think you have the numbers backwards. To test inlining, you must have the large loop calling the procedure, with the small loop doing the counting. You'll never notice a compiler difference with only 10 procedure calls.
I used these procedures for my tests:
create or replace procedure p2 is
n number:=0;
begin
for i in 1..5 loop
n:=n+1;
end loop;
end;
/
create or replace procedure CALL_PROC_ARITH2 is
begin
for i in 1..10000000 loop
p2;
end loop;
end;
/
--Check the PL/SQL optimize level for the objects.
select name, plsql_optimize_level, plsql_code_type
from all_plsql_object_settings
where owner = user
and name like 'CALL_PROC%' or name like 'P_';
4. Is your testing method robust enough?
Your tests should try to compensate for other activity consuming the CPU. Run multiple small tests in alternating order, throw out the high and low values, and compare the averages. A five second difference from running a five minute test twice is not significant.
I used the below PL/SQL blocks to test run times. (You can build a PL/SQL program to run the blocks in random order and record the times. I did that part manually.)Level 3 and 2 run the same speed, level 1 is a tiny bit slower, and level 0 is significantly slower.
--Level 3: 3.331, 3.403, 3.419
alter session set plsql_optimize_level = 3;
alter procedure call_proc_arith2 compile;
alter procedure p2 compile;
begin
call_proc_arith2;
end;
/
--Level 2: 3.383, 3.470, 3.444
alter session set plsql_optimize_level = 2;
alter procedure call_proc_arith2 compile;
alter procedure p2 compile;
begin
call_proc_arith2;
end;
/
--Level 1: 3.867, 3.859, 3.873
alter session set plsql_optimize_level = 1;
alter procedure call_proc_arith2 compile;
alter procedure p2 compile;
begin
call_proc_arith2;
end;
/
--Level 0: 6.286, 6.296, 6.315
alter session set plsql_optimize_level = 0;
alter procedure call_proc_arith2 compile;
alter procedure p2 compile;
begin
call_proc_arith2;
end;
/
5. Do you even care about PL/SQL optimizations?
In most real-world PL/SQL programs, inlining procedures will not make a meaningful difference. The best practice is to do as much heavy lifting as possible with SQL. But regardless of where your logic is, make sure that you are using a profiler and only tuning parts of the program that take a significant amount of time. Before tuning part of a PL/SQL program, you should have some hard numbers, like "if I optimize line X the program could run up to Y% faster."
I have a stored procedure with out sys_refcursor return type. My requirement is to get the start and end time of execution of this stored procedure. how can I do that ?
The starttime should capture when procedure was called.
The endtime sould capture when procedure returned the response.
PS:- my requirement is not to print it on console as :-
dbms_output.put_line ('start procedure: ' || to_char(systimestamp, 'HH24:MI:SS.FF6'));
thanks
If you are using MSSQL then you can track with MS SQL Profiler with procedure name filter. and for mysql, you can enable the log from configuration.
Always procedure execution time doesn't help to us for better performance. Need to focus on commit/rollback or connection close time as well.
I've been trying to get SQL Developer to run a query automatically on a regular basis (on the sample HR database). Based on my research, I've determined that the best alternative for me would be to use the Job Wizard & PL/SQL (where it calls DBMS_SCHEDULER?).
I created a 'Schedule' that repeats every 5 minutes called: every_5mins
Here is what I have in the 'Job Details' section thus far:
Job Name: Select_Employees
Job Class: SYS.DEFAULT_JOB_CLASS
Type of Job: PL/SQL block
When to Execute Job: Schedule
Schedule: SYSTEM.EVERY_5MINS
PL/SQL
CREATE OR REPLACE
PROCEDURE get_emp_rs (p_deptno IN HR.FIRST_NAME,
p_recordset OUT SYS_REFCURSOR) AS
BEGIN
OPEN p_recordset FOR
SELECT FIRST_NAME,
LAST_NAME
FROM
HR.EMPLOYEES
WHERE FIRST_NAME=p_recordset
END;
/
it returns an error:
"Encountered the symbol "/" when expecting one of the following: (begin case declare)..." and the rest is cut off the screen
Am I on the right track? What is the proper way to write it so the query is run every 5 mins? I have never used Oracle SQL Developer before.
Thanks in advance.
I have a new error: line 1, column 750 PLS-00103: Encountered the symbol "CREATE"
The PL/SQL payload is the code we want our job to execute. So it seems you are trying to schedule the creation of stored procedure every five minutes. The scheduler is expecting an executable PL/SQL call, not DDL.
So what you need to to is create the stored procedure first, then fire up the Job wizard. The PL/SQL block should be something like this:
declare
rc sys_refcursor;
begin
get_emp_rs ('MAYZIE', rc);
end;
This points us to the underlying problem with your scenario: jobs run in the background. There's no way for a job to accept user input or display output. So while your job will run every five minutes you'll never see the result set. You need a procedure which writes results somewhere (a table, a file) which can be read and displayed by some other program.
I have a scenario, in which i have one stored proc which contains set of sql statements( combination of joins and sub queries as well, query is large to displays)
and finally result is storing in temp table.
this is executing by user from frontend or programmer from backend with specific permissions.
here the problem is, there is difference in execution time for this query.
sometimes it is taking 10 mins, sometimes it is taking 1 hour, but an average elapsed time is 10 mins, and one common thing is always it is giving the same amount of records (approximately same).
As ErikL mentioned checking the execution plan of the query is a good start. In Oracle 11g you can use the DBMS_PROFILER. This will give you information about the offending statements. I would run it multiple times and see what the difference is between multiple run times. First check to see if you have the DBMS_PROFILER installed. I believe it comes as a seperate package.
To start the profiler:
SQL> execute dbms_profiler.start_profiler('your_procedure_name');
Run your stored procedure:
SQL> exec your_procedure_name
Stop the profiler:
SQL> execute dbms_profiler.stop_profiler;
This will show you all statements in your store procedure and their associated run time, and this way you can narrow down the problem to possibly a single query that is causing the difference.
Here is the Oracle doc on DBMS_PROFILER:
Oracle DBMS PROFILER
If you are new to oracle then you can use dbms_output or use a logging table to store intermediate execution times, that way you will know which SQL is causing the issue.
declare
run_nbr number;
begin
run_nbr = 1; -- or get it from sequence
SQL1;
log(run_nbr ,user,'sql1',sysdate);
SQL2;
log(run_nbr ,user,'sql2',sysdate);
commit;
end;
here log procedure is nothing but simple insert statements which will insert into a table say "LOG" and which has minimal columns say run_nbr, user, sql_name, execution_date
procedure log(run_nbr number, user varchar2, sql_name varchar2, execution_date date)
is
begin
insert into log values(run_nbr, user, sql_name, execution_date);
-- commit; -- Un-comment if you are using pragma autonomous_transaction
end;
This is little time consuming to put these log statements, but can give you idea about the execution times. Later once you know the issue, you simply remove/comment these lines or take a code backup of your original procedure without these log statements and re-compile it after pin-pointing the issue.
I would check the execution plan of the query, maybe there are profiles in there that are not always used.
or if that doesn't solve it, you can also try tracing the session that calls the SP from the frontend. There's a very good explanation about tracing here: http://tinky2jed.wordpress.com/technical-stuff/oracle-stuff/what-is-the-correct-way-to-trace-a-session-in-oracle/
how can i run one query in pl-sql- in parallel?
i need all the flow...
You can create JOBs in order to run the same query with parallelism.
EXAMPLE
CREATE OR REPLACE PROCEDURE target_deletion
IS
number_of_the_job NUMBER;
BEGIN
DBMS_JOB.submit (number_of_the_job, 'begin stored_procedure_for_deletion; end;', SYSDATE);
END;
/
EXPLAINATION
Please suppose you have, in your Oracle DataBase, a stored procedure called exactly as follows:
stored_procedure_for_deletion
If you wish to execute that stored procedure many times with PARALLELISM, you have to create a stored procedure called for example "TARGET_DELETION" (written above), which creates a new job that invokes, with the PL/SQL block:
begin stored_procedure_for_deletion; end;
... the execution of your procedure called "stored_procedure_for_deletion".
The job starts immediately, so you can run the stored procedure target_deletion many consecutive times, in order to run the same procedure with parallelism.
If enabled at instance level, Oracle itself has parallel query features:
http://www.orafaq.com/wiki/Parallel_Query_FAQ
edit: it's not clear what you are trying to do. Maybe you want asynchronous query execution, so the Oracle job suggestion is correct (see the other answer).
Oracle parallel feature is not asynchronous, it just says the optimizer to use a certain number of CPUs in query execution, to speed up the result. For example:
select /*+ PARALLEL(DOGS,4) */ * from DOGS where A>20
executes your query with parallelism at degree 4.