Monitor stored procedure execution time in Oracle - oracle

Is there a way to monitor stored procedure execution time?
Also to do some operations if execution time takes more than some fixed time

For this is dbms_profiler package. Previously it should be set up for use. It creates a table service.
More details can be found in the documentation:
https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_profil.htm#BJEFDBBC

I don't know a direct way but you can use PL/SQL package DBMS_APPLICATION_INFO
Procedure MY_Procedure is
begin
DBMS_APPLICATION_INFO.SET_MODULE('MY_Procedure', 'Starting');
...
DBMS_APPLICATION_INFO.SET_ACTION('Still working, please be patient');
...
DBMS_APPLICATION_INFO.SET_ACTION('Finished');
END;
While the procedure is running you can query (and perform some actions if needed) by this:
SELECT SID, serial#, username, module, action, sql_exec_start
FROM v$session;
If needed you can also put a timestamp or execute time, e.g. DBMS_APPLICATION_INFO.SET_ACTION('Started at '||systimestamp)
In case you are working with Scheduler jobs you can monitor and stop the jobs directly:
BEGIN
DBMS_SCHEDULER.SET_ATTRIBUTE(
NAME => 'MY_JOB',
ATTRIBUTE => 'MAX_RUN_DURATION',
VALUE => INTERVAL '10' MINUTE);
END;
and the call this frequently:
DECLARE
CURSOR Jobs IS
SELECT JOB_NAME, LAST_START_DATE, MAX_RUN_DURATION
FROM USER_SCHEDULER_JOBS
WHERE JOB_NAME = 'MY_JOB'
AND STATE = 'RUNNING'
AND SYSTIMESTAMP - LAST_START_DATE > MAX_RUN_DURATION;
BEGIN
FOR aJob IN Jobs LOOP
DBMS_SCHEDULER.STOP_JOB('MY_JOB', FORCE => TRUE);
END LOOP;
END;

Related

How to execute a stored procedure in a different session in same time in pl/sql

Is there anyway possible in PL/SQL to invoke multiple sessions and run a procedure in the multiple sessions simultaneously.
I want to use this in a real time applications where there are 250 users logging into the application. The users are connected to Oracle through a client tool. (Power Builder is the Front End Tool)
For example, if an user calls an stored procedure, that stored procedure has to be run for 10 times with different parameter values.
I don't want to run this sequentially one after another for 10 times in the same session because it may take long time.
I am looking for a way where I can run the stored procedure in 10 different sessions simultaneously.
I thought about placing 10 jobs using DBMS_JOB.SUBMIT but because of
the heavy job load ( 250 users * 10 = 2500 jobs may be scheduled in the Job scheduler at the same time and so on) our DBA group is looking for some other better way.
To avoid posting several Oracle jobs, you could try using William Robertson Parallel PL/SQL launcher.
if you create a table "PQ_DRIVER" with 4 partitions and a parallel degree of 4, with one row in each partition, and you execute a query along the lines of "SELECT /*+ PARALLEL(pq,4) */ thread_id FROM pq_driver pq", that should persuade the PQ controller to set four PQ slave processes to work on it (one per partition). And if you pass that query as a cursor parameter to a parallel-enabled pipelined function, then shouldn't that create a situation where each each row is processed by a separate PQ slave process? So here is a way to use (alright, hack) the PQ engine so that it processes arbitrary PL/SQL procedure calls in parallel.
The idea is to create a function using PARALLEL_ENABLE and PIPELINED features:
function pq_submit
( p_job_list varchar2_tt
, p_pq_refcur rc_pq_driver )
return varchar2_tt
parallel_enable(partition p_pq_refcur by any)
pipelined
is
...
loop
execute_command(your_proc);
end loop;
Function execute_command uses autonomous_transaction.
It looks like this:
procedure execute_command
( p_what log_times.what%type )
is
pragma autonomous_transaction;
begin
execute immediate p_what;
commit;
end execute_command;
Alternatively to creating JOBs you may use the DBMS_PARALLEL_EXECUTE package.
Here some hits:
Use create_chunks_by_sql with by_rowid => FALSE, i.e. using ID and create exact the same number of chunks as the required execution of the stored procedure.
In run_task set the parallel_level to the required degree of parallelism. This is the same number as above or lower if you need o throttle the parallelism.
Pass the call of the
procedure as the parameter sql_stmt e.g.
BEGIN
test_proc(:start_id,:end_id);
END;
Optionally as you see it is possible to pass the chunk number to the procedure, so you may use it as a threadId.
Here a complete example
Create task and 3 chunks
DECLARE
l_stmt CLOB;
BEGIN
DBMS_PARALLEL_EXECUTE.create_task (task_name => 'parallel PL/SQL');
l_stmt := 'SELECT rownum, rownum FROM dual connect by level <= 3';
DBMS_PARALLEL_EXECUTE.create_chunks_by_sql(task_name => 'parallel PL/SQL',
sql_stmt => l_stmt,
by_rowid => FALSE);
END;
/
Run the task with DOP = 3
DECLARE
l_sql_stmt VARCHAR2(32767);
BEGIN
l_sql_stmt := 'BEGIN
test_proc(:start_id,:end_id);
END;';
DBMS_PARALLEL_EXECUTE.run_task(task_name => 'parallel PL/SQL',
sql_stmt => l_sql_stmt,
language_flag => DBMS_SQL.NATIVE,
parallel_level => 3);
END;
/
Remove the Task
BEGIN
DBMS_PARALLEL_EXECUTE.drop_task('parallel PL/SQL');
END;
/

Running PL/SQL calls in parallel and wait for execution to finish (fork and join)

In a legacy system there is some PL/SQL procedure that calls the another procedure mutliple times with different parameters. The procedure contains a lot of PL/SQL logic (if, then, else).
As the execution of this procedure takes very long, we thought about using concurrency to speed things up without even touching the actual logic.
I understand that there are several ways of running (PL/)SQL in parallel on oracle (see bellow).
However, I wasn't able to find a way to pass different arguments/parameters to a PL/SQL procedure, execute them in parallel and wait until all procedures are finished executing (i.e. I'm looking for mechanism to join all threads or for a barrier mechanism in oracle).
Let's use the following simplified example on the SCOTT Schema:
DECLARE
PROCEDURE DELETE_BONUS(
in_job IN VARCHAR2)
IS
BEGIN
-- Imagine a lot of IF, ELSEIF, ELSE statements here
DELETE FROM BONUS WHERE JOB=in_job;
END;
BEGIN
INSERT into BONUS(ENAME, JOB) SELECT ROWNUM, 'A' FROM DUAL CONNECT BY LEVEL <= 1000000;
INSERT into BONUS(ENAME, JOB) SELECT ROWNUM, 'B' FROM DUAL CONNECT BY LEVEL <= 1000000;
INSERT into BONUS(ENAME, JOB) SELECT ROWNUM, 'C' FROM DUAL CONNECT BY LEVEL <= 1000000;
-- TODO execute those in parallel
DELETE_BONUS('A');
DELETE_BONUS('B');
DELETE_BONUS('C');
-- TODO wait for all procedures to finish
EXCEPTION
WHEN OTHERS THEN
RAISE;
END;
/
Here's what I found so far:
DBMS_JOB (deprecated)
DBMS_SCHEDULER (how to wait for jobs to finish? LOCKS?)
DBMS_SCHEDULER CHAINS (passing parameters/arguments is not really possible?!)
DBMS_PARALLEL_EXECUTE (can be used to run SQL queries in parallel but not PL/SQL procedures)
Can one of these approaches be used to fork and join the procedure calls? Or is there yet another approach that can?
I solved the problem using DBMS_SCHEDULER and PIPEs for synchronization/IPC that does not rely on polling and does not need additional tables. It still wakes once per finished job, though.
It's quite some effort, so if some can propose a simpler solution please share it!
Define a procedure that calls the actual procedure that can be run
from a program/job and handles IPC (write message to pipe when finished).
Define a program that calls this procedure and defines arguments to be passed to the procedure
Define a procedure that creates a job from the program, maps parameters to job arguments and runs the job
Define logic that waits for all jobs to finish: Wait until every job has sent a message on the pipe.
--
-- Define stored procedures to be executed by job
--
/** Actual method that should be run in parallel*/
CREATE OR REPLACE PROCEDURE PROC_DELETE_TEST_BONUS(
in_job IN VARCHAR2)
IS
BEGIN
-- Imagine a lot of IF, ELSEIF, ELSE statements here
DELETE FROM TEST_BONUS WHERE JOB=in_job;
END;
/
/** Stored procedure to be run from the job: Uses pipes for job synchronization, executes PROC_DELETE_TEST_BONUS. */
CREATE OR REPLACE PROCEDURE PROC_DELETE_TEST_BONUS_CONCUR(in_pipe_name IN VARCHAR2,
in_job IN VARCHAR2)
IS
flag INTEGER;
BEGIN
-- Execute actual procedure
PROC_DELETE_TEST_BONUS(in_job);
-- Signal completion
-- Use the procedure to put a message in the local buffer.
DBMS_PIPE.PACK_MESSAGE(SYSDATE ||': Success ' ||in_job);
-- Send message, success is a zero return value.
flag := DBMS_PIPE.SEND_MESSAGE(in_pipe_name);
EXCEPTION
WHEN OTHERS THEN
-- Signal completion
-- Use the procedure to put a message in the local buffer.
DBMS_PIPE.PACK_MESSAGE(SYSDATE ||':Failed ' || in_job);
-- Send message, success is a zero return value.
flag := DBMS_PIPE.SEND_MESSAGE(in_pipe_name);
RAISE;
END;
/
--
-- Run Jobs
--
DECLARE
timestart NUMBER;
duration_insert NUMBER;
jobs_amount NUMBER := 0;
retval INTEGER;
message VARCHAR2(4000);
rows_amount NUMBER;
/** Create and define a program that calls PROG_DELETE_TEST_BONUS_CONCUR to be run as job. */
PROCEDURE create_prog_delete_test_bonus
IS
BEGIN
-- define new in each run in order to ease development. TODO Once it works, no need to redefine for each run!
dbms_scheduler.drop_program(program_name => 'PROG_DELETE_TEST_BONUS_CONCUR', force=> TRUE);
dbms_scheduler.create_program ( program_name => 'PROG_DELETE_TEST_BONUS_CONCUR', program_action =>
'PROC_DELETE_TEST_BONUS_CONCUR', program_type => 'STORED_PROCEDURE', number_of_arguments => 2,
enabled => FALSE );
dbms_scheduler.DEFINE_PROGRAM_ARGUMENT( program_name => 'PROG_DELETE_TEST_BONUS_CONCUR',
argument_position => 1, argument_name => 'in_pipe_name', argument_type => 'VARCHAR2');
dbms_scheduler.DEFINE_PROGRAM_ARGUMENT( program_name=>'PROG_DELETE_TEST_BONUS_CONCUR',
argument_position => 2, argument_name => 'in_job', argument_type => 'VARCHAR2');
dbms_scheduler.enable('PROG_DELETE_TEST_BONUS_CONCUR');
END;
/** "Forks" a job that runs PROG_DELETE_TEST_BONUS_CONCUR */
PROCEDURE RUN_TEST_BONUS_JOB(
in_pipe_name IN VARCHAR2,
in_job IN VARCHAR2,
io_job_amount IN OUT NUMBER)
IS
jobname VARCHAR2(100);
BEGIN
jobname:=DBMS_SCHEDULER.GENERATE_JOB_NAME;
dbms_scheduler.create_job(job_name => jobname, program_name =>
'PROG_DELETE_TEST_BONUS_CONCUR');
dbms_scheduler.set_job_argument_value(job_name => jobname, argument_name =>
'in_pipe_name' , argument_value => in_pipe_name);
dbms_scheduler.set_job_argument_value(job_name => jobname, argument_name =>
'in_job' , argument_value => in_job);
dbms_output.put_line(SYSDATE || ': Running job: '|| jobname);
dbms_scheduler.RUN_JOB(jobname, false );
io_job_amount:= io_job_amount+1;
END;
-- Anonymous "Main" block
BEGIN
create_prog_delete_test_bonus;
-- Define private pipe
retval := DBMS_PIPE.CREATE_PIPE(DBMS_PIPE.UNIQUE_SESSION_NAME, 100, FALSE);
dbms_output.put_line(SYSDATE || ': Created pipe: ''' || DBMS_PIPE.UNIQUE_SESSION_NAME || ''' returned ' ||retval);
timestart := dbms_utility.get_time();
INSERT into TEST_BONUS(ENAME, JOB) SELECT ROWNUM, 'A' FROM DUAL CONNECT BY LEVEL <= 1000000;
INSERT into TEST_BONUS(ENAME, JOB) SELECT ROWNUM, 'B' FROM DUAL CONNECT BY LEVEL <= 1000000;
INSERT into TEST_BONUS(ENAME, JOB) SELECT ROWNUM, 'C' FROM DUAL CONNECT BY LEVEL <= 1000000;
COMMIT;
duration_insert := dbms_utility.get_time() - timestart;
dbms_output.put_line(SYSDATE || ': Duration (1/100s): INSERT=' || duration_insert);
SELECT COUNT(*) INTO rows_amount FROM TEST_BONUS;
dbms_output.put_line(SYSDATE || ': COUNT(*) FROM TEST_BONUS: ' || rows_amount);
timestart := dbms_utility.get_time();
-- -- Process sequentially
-- PROC_DELETE_TEST_BONUS('A');
-- PROC_DELETE_TEST_BONUS('B');
-- PROC_DELETE_TEST_BONUS('C');
-- start concurrent processing
RUN_TEST_BONUS_JOB(DBMS_PIPE.UNIQUE_SESSION_NAME, 'A', jobs_amount);
RUN_TEST_BONUS_JOB(DBMS_PIPE.UNIQUE_SESSION_NAME, 'B', jobs_amount);
RUN_TEST_BONUS_JOB(DBMS_PIPE.UNIQUE_SESSION_NAME, 'C', jobs_amount);
-- "Barrier": Wait for all jobs to finish
for i in 1 .. jobs_amount loop
-- Reset the local buffer.
DBMS_PIPE.RESET_BUFFER;
-- Wait and receive message. Timeout after an hour.
retval := SYS.DBMS_PIPE.RECEIVE_MESSAGE(SYS.DBMS_PIPE.UNIQUE_SESSION_NAME, 3600);
-- Handle errors: timeout, etc.
IF retval != 0 THEN
raise_application_error(-20000, 'Error: '||to_char(retval)||' receiving on pipe. See Job Log in table user_scheduler_job_run_details');
END IF;
-- Read message from local buffer.
DBMS_PIPE.UNPACK_MESSAGE(message);
dbms_output.put_line(SYSDATE || ': Received message on '''|| DBMS_PIPE.UNIQUE_SESSION_NAME ||''' (Status='|| retval ||'): ' || message);
end loop;
dbms_output.put(SYSDATE || ': Duration (1/100s): DELETE=');
dbms_output.put_line(dbms_utility.get_time() - timestart);
SELECT COUNT(*) INTO rows_amount FROM TEST_BONUS;
dbms_output.put_line(SYSDATE || ': COUNT(*) FROM TEST_BONUS: ' || rows_amount);
retval :=DBMS_PIPE.REMOVE_PIPE(DBMS_PIPE.UNIQUE_SESSION_NAME);
dbms_output.put_line(systimestamp || ': REMOVE_PIPE: ''' || DBMS_PIPE.UNIQUE_SESSION_NAME || ''' returned: ' ||retval);
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SYSDATE || SUBSTR(SQLERRM, 1, 1000) || ' ' ||
SUBSTR(DBMS_UTILITY.FORMAT_ERROR_BACKTRACE, 1, 1000));
retval := DBMS_PIPE.REMOVE_PIPE(DBMS_PIPE.UNIQUE_SESSION_NAME);
dbms_output.put_line(SYSDATE || ': REMOVE_PIPE: ''' || DBMS_PIPE.UNIQUE_SESSION_NAME || ''' returned: ' ||retval);
-- Clean up in case of error
PROC_DELETE_TEST_BONUS('A');
PROC_DELETE_TEST_BONUS('B');
PROC_DELETE_TEST_BONUS('C');
RAISE;
END;
/
You should always keep in mind that the changes executed within the job are committed in a separate transaction.
Just to get a feeling for what this concurrency achieves, here a some averaged measured values: The sequential code in the question takes about 60s to complete, the parallel one about 40s.
It would be an interesting further investigation how this turns out when there are more than the three jobs running in parallel.
PS
A helpful query to find out about the status of the jobs is the following
SELECT job_name,
destination,
TO_CHAR(actual_start_date) AS actual_start_date,
run_duration,
TO_CHAR((ACTUAL_START_DATE+run_duration)) AS actual_end_date,
status,
error#,
ADDITIONAL_INFO
FROM user_scheduler_job_run_details
ORDER BY actual_start_date desc;
Just wanted to add a few notes about DBMS_PARALLEL_EXECUTE package from Oracle.
This can be used to do more than update a table, although many of the examples show this simple use case.
The trick is to use an anonymous block instead of a DML statement, and the rest of the examples are still relevant. So, instead of this:
l_sql_stmt := 'update EMPLOYEES e
SET e.salary = e.salary + 10
WHERE manager_id between :start_id and :end_id';
We might have this:
l_sql_stmt := 'BEGIN my_package.some_procedure(:start_id, :end_id); END;';
The rest of the example can be found in the "Chunk by User-Provided SQL" example section
You will still need to tell Oracle the start/end ids for each process(using CREATE_CHUNKS_BY_SQL), I typically store them in a separate lookup table (if pre-defined) or you can provide a SQL query that returns a set of start/end values. For the latter approach, try using NTILE. For example, using 8 chunks:
select min(id) as start_id, max(id) as end_id
from (
select id, ntile(8) over (order by 1) bucket
from some_table
where some_clause...
)
group by bucket
order by bucket;
Hope that helps
If yes, you can try this:
create a new table with tasks (and parameter of tasks)
create procedure that will read parameters from table, pass them to "legacy procedure" and then update task table after processing (using autonomous transactions) to show that processing is ended
outer procedure, that creates tasks, can scan task table to get information about progress. You can use DBMS_LOCK.SLEEP to wait.

Find the job ID of the currently running job / allow only a single job to update a table

I have a "star" database. One is doing some work; another two have jobs that pull metadata into their reference tables, from the first database. I want to stop anyone from updating, deleting or inserting any records on the reference tables in the two "slaves"; the tables should just be updated by the scheduled job.
I'm currently doing this with a trigger that checks to see if the current SID is in USER_SCHEDULER_RUNNING_JOBS with the job name I expect to be running. I'd like to change this to use the JOB_ID of the job I'm running from.
This is my current set-up; assume a really simple table:
create table a ( b number );
and the following job:
begin
dbms_scheduler.create_job(
job_name => 'test_job'
, job_type => 'PLSQL_BLOCK'
, job_action => 'begin
merge into a a
using ( select 1 x from dual#db2 ) b
on (1 = 2)
when not matched then
insert values (b.x);
commit;
end;'
, start_date => sysdate
, repeat_interval => 'FREQ = MINUTELY;'
, enabled => true
);
end;
/
I'm using this trigger:
create or replace trigger tr_blah
before insert or update on a
declare
l_ct number;
begin
select count(*) into l_ct
from user_scheduler_running_jobs
where session_id = sys_context('USERENV','SID')
and job_name = 'TEST_JOB'
;
if l_ct = 0 then
raise_application_error(-20000, 'FAIL');
end if;
end;
/
This is inelegant; but, worse, I have to create a separate trigger for each table in each database and change the job name each time. There's no way of dynamically creating the trigger; this gets tiresome and there's a lot of scope for errors creeping in.
SYS_CONTEXT() has the parameters FG_JOB_ID and BG_JOB_ID. Their description, especially that of FG_JOB_ID implies that they might be the JOB_ID of the currently running job. Changing the trigger to the following (I've tried both):
create or replace trigger tr_a
before insert or update or delete on a
declare
l_ct number;
begin
raise_application_error(-20000, sys_context('USER_ENV', 'BG_JOB_ID'));
end;
/
Results in the following
ORA-20000:
ORA-06512: at "REF.TR_A", line 4
ORA-04088: error during execution of trigger 'REF.TR_A'
ORA-06512: at line 2
This implies that both FG_JOB_ID and BG_JOB_ID are null. Is there a method of determining the ID of the job running in the current session so I don't need to use JOB_NAME each time?
Most elegant solution is to use different database users. Make sure the job runs under a user that has update, insert and delete grants on the tables (possible the schema owner of the tables). Don't give these grants to the other users.
No need to mess around with triggers and such.

Finding the job number in an exception handler

I have some Oracle jobs running. In each job I have set up a PL/SQL exception handler that sends an email to developers if there is an error encountered in the code the job runs. Is there a way for me to know in the exception handler the job number so I can include that in the email?
Something like:
BEGIN
Run_This_Plsql();
EXCEPTION WHEN OTHERS DO
DECLARE
job_number VARCHAR2(64);
BEGIN
job_number := --This would be the job number of the currently running job
Send_email(job_number, subject, recipient, from);
END;
END;
While searching, I found this post in OraFAQs forum highlighting BG_JOB_ID parameter of sys_context function - give it a try.
BEGIN
Run_This_Plsql();
EXCEPTION WHEN OTHERS DO
DECLARE
job_number VARCHAR2(64);
BEGIN
job_number := sys_context('userenv', 'BG_JOB_ID');
Send_email(job_number, subject, recipient, from);
END;
END;
If you are talking about dbms_job then you can simply use job parameter. Let's say you have following procedure
procedure do_the_job(p_job_no in number) is
begin
...
exception
when others then
send_email(p_job_no, ...);
end;
then you can pass job number to the procedure like this:
declare
l_job_no number;
begin
dbms_job.submit(job => l_job_no, what => 'do_the_job(job);');
end;
/
To build on your suggested solution.
I would store the oracle Job number in a table and read this number when the process starts
you can then create logging, status, email detail tables that all relate to the job number.
here's some pseudocode:
BEGIN
SELECT oracle_job_no INTO v_job_no FROM Myjobs WHERE jobName='Daily doodah';
job_start(v_job_no); -- log job start
Run_This_Plsql(v_job_no);
job_end(v_job_no); -- log job end
EXCEPTION WHEN OTHERS DO
DECLARE
BEGIN
Job_fail(v_job_no); -- log job failure, send email, etc
END;
END;
or just use an off the shelf scheduling system that does all of this and more e.g autosys
If you want session info (session id for example, or any other session info), then you might try (choose columns you wish to report/log):
select * from v$session where sid=(select sys_context('USERENV','SID') from dual);
Hope that helps

Can a JOB be created dynamically inside a trigger?

The execution of this trigger fails (it compiles but once I do the specified insert -> error)
create or replace
TRIGGER AFT_INSERT_TMP_TBL
AFTER INSERT ON TMP_TBL
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
DECLARE
V_SQL VARCHAR2(1000);
A_NAME VARCHAR2(100);
BEGIN
A_NAME:='ANY_NAME';
V_SQL:='BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => '''||A_NAME||''',
job_type => ''PLSQL_BLOCK'',
job_action => ''BEGIN DBMS_OUTPUT.PUT_LINE('||A_NAME||'); END;'',
start_date => TIMESTAMP''2011-12-4 10:30:00'',
repeat_interval => ''FREQ=MINUTELY;INTERVAL=2'',
auto_drop => FALSE,
comments => '''||A_NAME||''');
END;';
DBMS_OUTPUT.PUT_LINE('SCHEDULER :'||V_SQL);
EXECUTE IMMEDIATE V_SQL;
END AFT_INSERT_TMP_TBL;
-----------------------
Printed SCHEDULER creation code is totally valid.
I am getting a ORA-04092 'cannot in a trigger... A trigger attempted to commit or rollback. Rewrite the trigger so it doesn't commit or rollback'.
Is this a 'commit'? So a JOB cannot be created inside of a trigger?
I know I've used triggers with inserts into different tables, and that is also a "commit"
and Oracle didn't complaint.
Calling DBMS_SCHEDULER.CREATE_JOB implicitly commits so you cannot create a DBMS_SCHEDULER job in a trigger. This is one of the situations that still call for using the old DBMS_JOB package since DBMS_JOB.SUBMIT does not implicitly commit.
This trigger should create the job you want using the DBMS_JOB package rather than DBMS_SCHEDULER.
create or replace
TRIGGER AFT_INSERT_TMP_TBL
AFTER INSERT ON TMP_TBL
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
DECLARE
V_SQL VARCHAR2(1000);
A_NAME VARCHAR2(100);
l_jobno NUMBER;
BEGIN
A_NAME:='ANY_NAME';
dbms_job.submit( l_jobno,
'BEGIN dbms_output.put_line( ''' || a_name || ''' ); END;',
sysdate + interval '2' minute,
'sysdate + interval ''2'' minute' );
DBMS_OUTPUT.PUT_LINE('Job Number:'||l_jobno);
END AFT_INSERT_TMP_TBL;
You can also consider autonomous transaction
https://community.oracle.com/thread/2399412?start=0&tstart=0
Yes this is a commit. Oracle is updating a system table, job$ I think, when you create a scheduler or a job etc which means an automatic commit.
Why don't you just insert the information you need into another (driver) table and have a cron job or a dbms_job to create your scheduler jobs?

Resources