Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Keith.

Asked: August 24, 2001 - 5:11 pm UTC

Last updated: October 26, 2006 - 12:26 pm UTC

Version: 8.1.7

Viewed 10K+ times! This question is

You Asked

Tom,

I have a job (dbms_job) running (Win2000 w/ 8.1.7) that executes a procedure to update a column (on_sale_flag) value to 'false' if the offsale date (sale_end_date) is less than the sysdate. The job is supposed to run every hour on the hour. If I run the procedure independently, the update is immediate. When the job runs the procedure, it takes minutes for the update to occur throwing off the update schedule. The job is not broken and has not had any failures. Can you tell me why it takes so long for the job to run the procedure and what I can do to make the job run faster? We were previously using perl scripts and Win2000 AT scheduler to accomplish this task but for some reason the AT scheduler on the server does not want to work for more than 24 hours so this unfortunately is no longer an option. As always, thanks.

Keith

and Tom said...

do you know that the job runs slower?

Look at the TOTAL_TIME, remember that time, after the next run -- look at total time again. The difference will be the runtime.

What is more likely happening is "slippage". The job queues are inspected every N seconds where you control N (job_queue_interval). If this is set to 60 seconds for example -- then your job might run at 12:01 instead of 12:00. If you compute the next interval like this:

'sysdate+1/24'

your job might next be scheduled for 1:02 (see job NEXT_DATES are computed BEFORE the job runs -- that is why I doubt the length of the job runtime has anything to do with this. If the job took 5 minutes -- it would not matter, the next_date was already computed).

When the job runs next -- it might be 1:03 -- the next date will be 2:03. At 2:04 it gets run and so on. Over time -- it slips.

So, how to get it as close to the hour on the hour? Use a FIXED computation on time -- not a sliding one. Use:

'trunc(sysdate,''hh'')+1/24'

then, when the job does run at 12:01 -- the NEXT_DATE it computes will be 1:00 -- NOT 1:01. It won't slip anymore.


Also bear in mind that if you use jobs lots -- your job_queue_processes could be coming into play as well. If a job is running at 1pm (not your job, some other job) and you have job_queue_processes = 1, then you will WAIT until that job is done. Just increment your job_queue_processes.


If you really need the job to run at exactly the hour on the hour -- schedule the job a little BEFORE the hour. then, have it sleep for N seconds. Eg: say your job_queue_interval is 60 (1 minute -- very reasonable). You might schedule the job to run at xx:58 instead of xx:00 using:

'round(sysdate,''hh'')+58/24/60'

What that will do is when its just before/after the hour, it'll round the time to the nearest hour and add 58 minutes:

1* select sysdate, round(sysdate,'hh')+58/24/60 from dual
ops$tkyte@ORA817.US.ORACLE.COM> /

SYSDATE ROUND(SYSDATE,'HH')+
-------------------- --------------------
24-aug-2001 18:58:16 24-aug-2001 19:58:00

Now, your job should:

n := (round(sysdate,'hh')-sysdate)*24*60*60;
if ( n > 0 )
then
dbms_lock.sleep(n);
end if;


that way, if it is just a little before the appointed hour, it'll wait and then run. If it is on the hour or just after -- it'll run right away.





Rating

  (23 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

dbms_job

Phil, January 23, 2004 - 11:00 am UTC

Hi Tom,

Just a quick bit on clarification of intervals please if you have a minute. We want to run jobs every 15 seconds, would it be better to have a process that somehow continually runs? EG, we have a dbms_job to run every 10 minutes or so which checks the procedure is running and if not starts it. And the procedure itself has the following at the bottom following which it just calls itself (actually is this allowed in a dbms_job?) so that the 15 seconds is guaranteed and not a function of running the dbms_job so quickly?

Thanks!


begin
sp body...
n := (round(sysdate,'hh')-sysdate)*24*60*60;
if ( n > 0 )
then
dbms_lock.sleep(n);
end if;
start sp again...
end;

(But set for 15 seconds - sorry not sure on the n:=?? section) that waits for 15 secs? Actually, we'd have to alter that a bit as the SP may take 1-3 secs to run.

I see this making the running of the process more controlled as the job_queue_interval of 15 looks like it is a bit close to the max we can have? I notice in 9i we don't actually have the interval parameter any more?

Tom Kyte
January 23, 2004 - 6:29 pm UTC

why/what are you doing every 15 seconds?

Job process killed. But still show the job running

Prince Faran, January 24, 2004 - 6:18 am UTC

Respected Tom!

(Oracle9i Release 2 on Windows 2000)

I have two following jobs are running to replicate the data.

SQL> SELECT SID, r.JOB, LOG_USER, r.THIS_DATE, r.THIS_SEC
  2  FROM   DBA_JOBS_RUNNING r, DBA_JOBS j
  3  WHERE  r.JOB = j.JOB;

       SID        JOB LOG_USER    THIS_DATE THIS_SEC
---------- ---------- ----------- --------- --------
       129          6 REPADMIN    23-JAN-04 19:16:28
        51          9 REPADMIN    24-JAN-04 14:26:15

One job has been running from yesterday. But there are lot of transactions pending in the queue. I have seen the status of this SID i.e. 129 => this session has put the locks. Then I have killed the session. It is marked as Killed. 

SQL> EXECUTE dbms_job.run(6);

PL/SQL procedure successfully completed.

SQL> SELECT SID, r.JOB, LOG_USER, r.THIS_DATE, r.THIS_SEC
  2  FROM   DBA_JOBS_RUNNING r, DBA_JOBS j
  3  WHERE  r.JOB = j.JOB;

       SID        JOB LOG_USER    THIS_DATE THIS_SEC
---------- ---------- ----------- --------- --------
       129          6 REPADMIN    23-JAN-04 19:16:28
        51          9 REPADMIN    24-JAN-04 14:26:15

But the job transactions from this job# 6 are not being applied ...

One thing I have to resolve the issue is to restart the database. It releases the Job Locks and then re-establish the session and it takes a minute to propagate the transactions queued by job# 6. My questions is "How can I avoid the restart to release the resources?"

Regards,

Faran 

dbms_job

Phil, January 24, 2004 - 2:01 pm UTC

Tom,

The job is inspecting a target table for certain status changes etc. We can not touch this system so can't use a trigger/snapshot afraid.

The design is more or less finalised, we just need to see if we could use a dbms_job less often to just ensure a process is running (the SP would run continually) rather than use a dbms_job running every 15 secs. Would a SP that runs and sleeps at the end, restarting itself be OK in your opinion?


Tom Kyte
January 24, 2004 - 2:48 pm UTC

why cannot you use the most effective methods? do you want to really hurt the system or just impact it a tiny bit? oh well. query like heck away....

I would not run an infinite job in the job queue. I'd have it execute maybe 10 times or so

create procedure this_procedure
as
begin
for i in 1 .. 10
loop
... do whatever ...
dbms_lock.sleep(15);
end loop;
dbms_job.submit( l_job, 'this_procedure;' );
commit;
end;



that'll give you a chance to shutdown every now and again "nicely" if you need and prevent any issues with long running procedures (memory buildup, whatever)




dbms_job

Phil, January 25, 2004 - 6:02 pm UTC

I totally agree with you on being a shame we can not do this in a more integrated manner but it has been imposed on us - thanks for your advice, that makes a lot of sense about limiting it to a number of iterations.


Can we call OS using DBMS_JOB?

A Reader, June 30, 2004 - 11:07 am UTC

Hi Tom,

I want to call a OS command or a batch file using Oracle DBMS_JOB. Can I do this? If I can, how?
Thank you for your help.

What is happening!!!!!!!!!!!

A reader, August 14, 2004 - 2:47 pm UTC

Hi Tom,
This query is in a job:
select to_char(TRUNC(SYSDATE)+1+(21/24)+(55/24/60),'DD-Mon-YY HH24:MM:SS') from dual;
It should show me 15-Aug-04 21:55:00,
but on the other hand it shows me 15-Aug-04 21:08:00.
We want the job to execute every night at 9:55PM, but the user_jobs show me it executed at 21:08PM and the next_time is the same.
Why is it happening?
And how should I resolve it?
Thanks a TON, quite heavy I know ;)

Tom Kyte
August 14, 2004 - 4:14 pm UTC

MM = month

MI = minutes

August is the 8th month :) you just used the wrong format.

Total_time VALUE

Marianna, September 07, 2004 - 1:57 pm UTC

Hi Tom,
We are running ORACLE RAC on 9.2.0.4 with 2 nodes, I have a job scheduled to run once a day at 11am. My question is about TOTAL_TIME column value in jobs table. I was monitoring it running today and I am also logging start and end time of the job and it did take 17.73 minutes to run, but in jobs table I see value:
JOB LAST_DAY LAST_SEC TOTAL TIME
8 7-Sep-2004 11:00:01 11:00:01 5811.00000000000000...
In documentation it says that the value in seconds, so 5811 is over 96 minutes! And I know the job ran 17 minutes. Can you please let me know if I am doing something wrong in interpreting this value.
Thanks

Tom Kyte
September 07, 2004 - 2:32 pm UTC

sure, it ran 17 minutes this morning..... but that is just saying "this job has executed for 5,811 seconds since you first submitted it"

it is a total_time - over runs, summed up.

running order

Hector, July 05, 2005 - 9:03 am UTC

Hi Tom

What determines the order that jobs are run when submitted using dbms_job.

We have an application that could put many jobs into the queue. (> 1000)

I would have expected them to be processed in the order that they are submitted, but it appears that the next_date column of dba_jobs is being ignored. It runs them pretty close to the propper order but not quite.

As you can see, job_queue_processes is set to 8. (Oracle 9.2.0.5)

select job, this_date, next_date, total_time from user_jobs
where rownum < 14;

JOB THIS_DATE NEXT_DATE TOTAL_TIME
--------- ------------------- ------------------- ----------
269941 05-07-2005 13:25:26 04-07-2005 16:09:47 1856
269964 05-07-2005 13:34:57 04-07-2005 16:10:00 1285
269988 05-07-2005 13:38:14 04-07-2005 16:10:18 1088
270002 05-07-2005 13:42:03 04-07-2005 16:10:37 859
270004 05-07-2005 13:42:03 04-07-2005 16:10:50 859
270006 04-07-2005 16:11:03 0
270008 05-07-2005 13:43:45 04-07-2005 16:11:14 757
270010 04-07-2005 16:11:26 0
270012 05-07-2005 13:47:37 04-07-2005 16:11:40 525
270014 05-07-2005 13:52:15 04-07-2005 16:12:45 247
270104 04-07-2005 16:48:47 0
270106 04-07-2005 16:49:02 0
270108 04-07-2005 16:49:17 0

13 rows selected.


Tom Kyte
July 05, 2005 - 9:45 am UTC

how did you submit them -- if you submitted them all "bam bam bam bam", then they will run in some order (it is based on the DATE, not a sequence or job_id).

How are you saying from the output above that "next_date" is being ignored?



running order

Hector, July 05, 2005 - 10:24 am UTC

Hi Tom

Yes the application does send them in in a "bam, bam, bam" fashion to run straight away (we don't code the next date).

The reason I'm querying the fact the next date is being ignored, is the fact that job 270008 starts running before 270006
and
270012 and 270014 have started before 270010

Tom Kyte
July 05, 2005 - 11:24 am UTC

but they were submitted in the same second so the order of "insertion" isn't "known" really. sequences are not "timed based", only time is -- there is no strict ordering of jobs in the job queue. Any N number of jobs all submitted with the same start time will be run in SOME order.

running order

Hector, July 06, 2005 - 5:25 am UTC

<snip>
the order of "insertion" isn't "known" really.
<snip>

but Tom, Surely the next_date value holds the running order. And it doesn't appear to be running them in next_date order

Tom Kyte
July 06, 2005 - 7:58 am UTC

when you submit:

ops$tkyte-ORA10G> declare
  2          l_job number;
  3  begin
  4          for i in 1 .. 10
  5          loop
  6                  dbms_job.submit( l_job, 'null;' );
  7          end loop;
  8  end;
  9  /
 
PL/SQL procedure successfully completed.
 
ops$tkyte-ORA10G>
ops$tkyte-ORA10G> @bigdate
ops$tkyte-ORA10G> alter session set nls_date_format = 'dd-mon-yyyy hh24:mi:ss';
 
Session altered.
 
ops$tkyte-ORA10G> select job, what, next_date from user_jobs;
 
       JOB WHAT                           NEXT_DATE
---------- ------------------------------ --------------------
       152 null;                          06-jul-2005 07:52:44
       153 null;                          06-jul-2005 07:52:44
       154 null;                          06-jul-2005 07:52:44
       155 null;                          06-jul-2005 07:52:44
       156 null;                          06-jul-2005 07:52:44
       157 null;                          06-jul-2005 07:52:44
       158 null;                          06-jul-2005 07:52:44
       159 null;                          06-jul-2005 07:52:44
       160 null;                          06-jul-2005 07:52:44
       161 null;                          06-jul-2005 07:52:44
 
10 rows selected.
 


they all had the same next_date, 161 can run before 152 but after 157.

it sorts by date, the job id is just a surrogate key and not meaningful. 

running order

Hector, July 06, 2005 - 8:07 am UTC

please look at the output from my original query.

They are not running in date order.

fyi the "bam bam bam" approach for our app actually gives about 15 seconds between submission.

Tom Kyte
July 06, 2005 - 8:27 am UTC

you are seeing the next_date after the first dates, the next_dates are recomputed.


question to you is what where their ORIGINAL next dates, when ORIGINALLY submitted, BEFORE the next date was set to an entirely NEW date.

the bam bam bam approach for 1,000 things with 15 seconds means that 66 to 67 of them are scheduled to run simultaneously, in random order.


Look, if you need a specific, controlled and controllable order, you used the wrong technique, AQ (message queueing) would have been an appropriate technique.

Well it does sort, it seems

Vladimir Andreev, July 06, 2005 - 9:07 am UTC

Hi Hector,

A quick trace of the Job Queue Coordinator on my 9.2.0.4 instance on Linux reveals that it does retrieve the pending jobs in order:

SQL> select sid,serial# from v$session where program like '%CJQ0%';

       SID    SERIAL#
---------- ----------
         7          1

SQL> exec dbms_system.set_ev(7,1,10046,1,'')

PL/SQL procedure successfully completed.

<submit and commit a dummy job and wait about one minute>

SQL> exec dbms_system.set_ev(7,1,10046,0,'')

PL/SQL procedure successfully completed.

The trace file contains the following statement, among two others:
*** SESSION ID:(7.1) 2005-07-06 14:31:05.495
=====================
PARSING IN CURSOR #1 len=245 dep=1 uid=0 oct=3 lid=0 tim=1094387759272670 hv=1316169839 ad='77d26488'
select job, nvl2(last_date, 1, 0) from sys.job$ where (((:1 <= next_date) and (next_date < :2))    or  ((last_date is null) and (next_date < :3))) and (field1 = :4 or (field1 = 0 and 'Y' = :5)) and (this_date is null) order by next_date, job
END OF STMT

Notice the order by <b>next_date, job</b>

Of course, I don't have a system that submits thousands of jobs, so you may want to trace your own CJQ while you have some active jobs to see what it is doing exactly.

But, in general, it was never documented that the jobs submitted via DBMS_JOB will run in any particular order, or exactly at particular times (to my knowledge, at least), so you cannot base an application design on that assumption.

Hope this helps.

Flado 

Tom Kyte
July 06, 2005 - 9:10 am UTC

you have multiple people pulling from this queue.

the next_dates he sees have been updated after the jobs (which run for varying lengths) have already run.

you will see job=1,2,3,4,5,6,7,8 get pulled to run.

5 finishes fast
1 takes long

you'll seeing varying next_dates based on that fact.



Yes, but still...

Vladimir Andreev, July 06, 2005 - 9:49 am UTC

Well, we don't see any intervals for these jobs, so we don't even know whether they will run more than once (and therefore get their next_date calculated more than once). And even if they did, keeping in mind that

<quote source=original answer above>
(see job NEXT_DATES are computed BEFORE the job runs -- that is why I doubt the length of the job runtime has anything to do with this. If the job took 5 minutes -- it would not matter, the next_date was already computed)
</quote>

, the order should hold (unless, of course, a job runs past its next_date, or if they have different INTERVALs).

Anyway, I'm not insisting that it MUST be so, just can't really understand why Hector's jobs don't start their first runs in submission (job_id) order. Race conditions could lead to such anomalies, but isn't the CJQ the only process that retrieves pending jobs and starts job slaves if necessary?

Regards,
Flado

Tom Kyte
July 06, 2005 - 10:48 am UTC

some of them will run more than once -- some of the next_dates are computed.

but also consider, we don't know what time it was when this report

JOB THIS_DATE NEXT_DATE TOTAL_TIME
--------- ------------------- ------------------- ----------
269941 05-07-2005 13:25:26 04-07-2005 16:09:47 1856
269964 05-07-2005 13:34:57 04-07-2005 16:10:00 1285
269988 05-07-2005 13:38:14 04-07-2005 16:10:18 1088
270002 05-07-2005 13:42:03 04-07-2005 16:10:37 859
270004 05-07-2005 13:42:03 04-07-2005 16:10:50 859
270006 04-07-2005 16:11:03 0
270008 05-07-2005 13:43:45 04-07-2005 16:11:14 757
270010 04-07-2005 16:11:26 0
270012 05-07-2005 13:47:37 04-07-2005 16:11:40 525
270014 05-07-2005 13:52:15 04-07-2005 16:12:45 247
270104 04-07-2005 16:48:47 0
270106 04-07-2005 16:49:02 0
270108 04-07-2005 16:49:17 0

13 rows selected.

was run. is job 270006 currently running, see how all of the jobs are taking different amounts of time here?




Let me hypothesise, then...

Vladimir Andreev, July 07, 2005 - 11:05 am UTC

OK, let's test our powers of observation, since Hector doesn't seem keen to provide us with the things we don't know :-)

Facts we know:
1. The default for NEXT_DATE is SYSDATE.
2. SYSDATE has a resolution of one second.
3. TOTAL_TIME is incremented while the job runs.

Observations on Hector's report:
A. The jobs that run currently have NEXT_DATEs which are almost a day earlier than their respective THIS_DATEs.
B. None of the currently running jobs has a TOTAL_TIME more than 31 minutes (1860 seconds)
C. The NEXT_DATEs of all jobs are no less than 11 seconds apart.
D. All the non-running jobs have a TOTAL_TIME of 0.
E. For all running jobs, adding the TOTAL_TIME to THIS_DATE yelds the magical mystical moment of 05-jul-2005 13:56:22
F. Job 270006 does not have a THIS_DATE

Educated guess 1: All the jobs listed have been submitted between 16:09 and 16:49 on July 4 with a 10-15 seconds' pause between the consecutive submissions; all jobs were submitted without a next_date parameter (and also without an INTERVAL, but this is only a guess based purely on heuristics).
This is basically what Hector said about his system - and it doesn't contradict the observations or facts. Hence, we don't need to worry about fact 2 (SYSDATE's resolution of 1 second) - the jobs were submitted with different next_dates.

Educated guess 2: The report was run at 05-jul-2005 13:56:22. I give this one a high degree of confidence based on Observation E above :-). This also indicates (very strongly, but doesn't prove, since all their previous runs could have taken a total of less than a second) that this is the first run of all running jobs, so they didn't have their NEXT_DATEs ever recalculated.

To summarize and answer your question:
Job 270006 is not currently running, because all 8 job slaves are busy running other jobs.
The jobs are taking different amounts of time only because they started at different times. They haven't finished their first runs yet. We cannot say whether they will ultimately take "the same", "similar", or "very different" amounts of time.
The report was run at 13:56:22 on 05-jul-2005.

Let me try to restate the question:
Given that several jobs have been submitted with monotonously increasing (and therefore different) NEXT_DATEs and JOB_IDs, and also given that the CJQ is the only process that selects jobs for running, and it does so in ascending order by NEXT_DATE and JOB_ID, how come they run in a different order?

I could imagine that in a RAC environment, there would be more than one CJQ processes (one per instance), which would explain this phenomenon. Is that the case here?

Of course I could try to run a test to see if something similar happens in my (non-RAC) environment, but that would spoil the nice mental excercise, wouldn't it :-)

Regards,
Flado

Job Runs - Get nothing meaningful

Mark, August 05, 2005 - 12:26 pm UTC

Hi Tom,

I have the following Package I built based on information from the book "Oracle Wait Interface: A Practical Guide to Performance Diagnostics and Tuning" (Oracle Press - Shee, Deshpande, Gopalakrishnan 2004), an excellent book by the way.

My Table Defs are at the end:
CREATE OR REPLACE PACKAGE HT4.DC_COLLECTOR
AS
PROCEDURE dc;

FUNCTION capture_sql (
in_wer_id NUMBER
,in_hash_value IN v$session.sql_hash_value%TYPE
,in_event IN v$session_wait.event%TYPE
,in_machine IN v$session.machine%TYPE
,in_module IN v$session.module%TYPE
,in_mode IN VARCHAR2 DEFAULT NULL
)
RETURN BOOLEAN;
END;
/
CREATE OR REPLACE PACKAGE BODY HT4.DC_COLLECTOR
AS
/* global cursor */
CURSOR current_event
IS
SELECT a.sid, a.seq#, a.event, a.p1text, a.p1, a.p1raw, a.p2text, a.p2,
a.p2raw, a.p3text, a.p3, a.p3raw, a.wait_time, a.seconds_in_wait,
a.state, b.serial#, b.username, b.osuser, b.paddr, b.logon_time,
b.process, b.sql_hash_value, b.saddr, b.module, b.row_wait_obj#,
b.row_wait_file#, b.row_wait_block#, b.row_wait_row#, b.machine
FROM v$session_wait a, v$session b
WHERE a.sid = b.sid
AND b.username IS NOT NULL
AND b.TYPE <> 'BACKGROUND'
AND a.event IN (
'db file sequential read',
'db file scattered read',
'latch free',
'direct path read',
'direct path write',
'enqueue',
'library cache pin',
'library cache load lock',
'buffer busy waits',
'free buffer waits'
);

rec current_event%ROWTYPE;

PROCEDURE dc
AS
CURSOR get_obj_name(
in_p1 IN v$session_wait.p1%TYPE,
in_p2 v$session_wait.p2%TYPE
)
IS
SELECT segment_name, partition_name
FROM dba_extents_rep
WHERE in_p2 BETWEEN block_id AND (block_id + blocks - 1)
AND file_id = in_p1;

CURSOR c_dbfn(
in_p1 v$session_wait.p1%TYPE
)
IS
SELECT name, 'DATAFILE' filetype
FROM v$datafile
WHERE file# = in_p1
UNION ALL
SELECT a.name, 'TEMPFILE' filetype
FROM v$tempfile a, v$parameter b
WHERE b.name = 'db_files'
AND a.file# + b.VALUE = in_p1;

CURSOR c_segtype(
in_saddr IN v$session.saddr%TYPE,
in_serial# IN v$session.serial#%TYPE
)
IS
SELECT DISTINCT DECODE(
ktssosegt, 1, 'SORT', 2, 'HASH', 3, 'DATA', 4,
'INDEX', 5, 'LOB_DATA', 6, 'LOB_INDEX',
'UNDEFINED'
) AS segtype
FROM sys.x_$ktsso
WHERE inst_id = USERENV('instance')
AND ktssoses = in_saddr
AND ktssosno = in_serial#;

CURSOR c_sesslockinfo(
in_p2 IN v$session_wait.p2%TYPE,
in_p3 v$session_wait.p3%TYPE
)
IS
SELECT a.sid, a.serial#, a.username, a.paddr, a.logon_time,
a.sql_hash_value, b.TYPE, b.lmode, b.ctime
FROM v$session a, v$lock b
WHERE a.sid = b.sid
AND b.id1 = in_p2
AND b.id2 = in_p3
AND b.block = 1;

CURSOR c_tob(
in_p1 IN v$session_wait.p1%TYPE,
in_p2 IN v$session_wait.p2%TYPE
)
IS
SELECT segment_type || ' header block'
FROM dba_segments
WHERE header_file = in_p1
AND header_block = in_p2
UNION ALL
SELECT segment_type || ' freelist group block'
FROM dba_segments
WHERE header_file = in_p1
AND in_p2 BETWEEN header_block + 1 AND (
header_block +
freelist_groups
)
AND freelist_groups > 1
UNION ALL
SELECT segment_type || ' data block'
FROM dba_extents
WHERE in_p2 BETWEEN block_id AND (block_id + blocks - 1)
AND file_id = in_p1
AND NOT EXISTS(SELECT 1
FROM dba_segments
WHERE header_file = in_p1
AND header_block = in_p2);

CURSOR c_blockinginfo(
in_p1raw IN v$session_wait.p1raw%TYPE
)
IS
SELECT a.sid, a.serial#, a.username, a.paddr, a.logon_time,
a.sql_hash_value, b.kglpnmod
FROM v$session a, sys.x_$kglpn b
WHERE a.saddr = b.kglpnuse
AND b.inst_id = USERENV('instance')
AND b.kglpnreq = 0
AND b.kglpnmod NOT IN (0, 1)
AND b.kglpnhdl = in_p1raw;

/* variable Declarations for specific event processing */
v_segment_name dba_extents_rep.segment_name%TYPE;
v_partition_name dba_extents_rep.partition_name%TYPE;
v_latchname v$latchname.name%TYPE;
v_object_name wait_events_repository.object_name%TYPE;
v_subobject_name dba_objects.subobject_name%TYPE;
v_datafile v$datafile.name%TYPE;
v_blocking_hash_value v$session.sql_hash_value%TYPE;
v_filetype VARCHAR2(100);
v_segtype VARCHAR2(10);
v_lock_mode VARCHAR2(10);
v_lock_type NUMBER;
v_wer_id NUMBER;
blnrtn BOOLEAN := FALSE;
v_stillrunning NUMBER := 0;
v_jobid NUMBER;
BEGIN
-- Examine DBA_JOBS_RUNNING to make sure this is not still running or hung
BEGIN
BEGIN
SELECT job
INTO v_jobid
FROM user_jobs
WHERE what LIKE '%DC_COLLECTOR%';
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN;
END;

SELECT COUNT(*)
INTO v_stillrunning
FROM dba_jobs_running d
WHERE d.job = v_jobid;

IF v_stillrunning <> 0
THEN
RETURN;
END IF;
END;

FOR rec IN current_event
LOOP
/* EVENT: db file sequential read/db file scattered read ### */
IF rec.event = 'db file sequential read'
OR rec.event = 'db file scattered read'
THEN
/* 1) Determine the object name and the partition name (if applicable)
using the P1 and P2 values supplied by the CURRENT_EVENT cursor
DBA_EXTENTS_REP table CURSOR GET_OBJ_NAME
*/
FOR rec_obj IN get_obj_name(rec.p1, rec.p2)
LOOP
v_object_name := rec_obj.segment_name;
END LOOP;
/* rec_sql: extract_sql */
END IF;/* 'db file sequential read', 'db file scattered read' */

/* EVENT: latch_free */
IF rec.event = 'latch free'
THEN
/* latch name */
SELECT name
INTO v_object_name
FROM v$latchname
WHERE latch# = rec.p2;
END IF;

/* EVENT: direct path read/direct path write */
IF rec.event = 'direct path read'
OR rec.event = 'direct path write'
THEN
/* OBJECT NAME */
FOR rec_obj IN get_obj_name(rec.p1, rec.p2)
LOOP
v_object_name := 'OBJ: ' || rec_obj.segment_name || ' ';
END LOOP;

/* db filename */
FOR rec_dbfn IN c_dbfn(rec.p1)
LOOP
v_object_name :=
v_object_name || 'DATAFILE: ' || rec_dbfn.name || ' ';
v_object_name :=
v_object_name || 'FILETYPE: ' || rec_dbfn.filetype || ' ';
END LOOP;

/* segment type */
FOR rec_segtype IN c_segtype(rec.saddr, rec.serial#)
LOOP
v_object_name :=
v_object_name || 'SEGTYPE: ' || rec_segtype.segtype;
END LOOP;

v_object_name := TRIM(v_object_name);
END IF;

/* EVENT: enqueue */
IF rec.event = 'enqueue'
THEN
/*
1) determine lock type and lock mode */
BEGIN
SELECT CHR(bitand(rec.p1, -16777216) / 16777215) ||
CHR(bitand(rec.p1, 16711680) / 65535) lock_mode,
MOD(rec.p1, 16) lock_type
INTO v_lock_mode,
v_lock_type
FROM dual;
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;

v_object_name :=
'LOCKMODE: ' || v_lock_mode || ' LOCK_TYPE: ' || v_lock_type || ' ';

/*
2) name of object */
BEGIN
SELECT object_name, subobject_name
INTO v_object_name,
v_subobject_name
FROM dba_objects
WHERE object_id = rec.row_wait_obj#;
v_object_name :=
'ENQOBJ: ' || v_object_name || ' ENQSOBJ: ' || v_subobject_name ||
' ';
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;

/*
3) blocking session and lock information */
FOR rec_sesslockinfo IN c_sesslockinfo(rec.p2, rec.p3)
LOOP
v_blocking_hash_value := rec_sesslockinfo.sql_hash_value;
v_object_name :=
v_object_name || ' BLOCKING SESSION - LOCK TYPE: ' ||
rec_sesslockinfo.TYPE ||
' LOCK MODE: ' ||
rec_sesslockinfo.lmode ||
' TIME LOCKED: ' ||
rec_sesslockinfo.ctime ||
' SQL_HASH: ' ||
rec_sesslockinfo.sql_hash_value;
END LOOP;
END IF;

/* EVENT: buffer busy waits */
IF rec.event = 'buffer busy waits'
THEN
FOR rec_obj IN get_obj_name(rec.p1, rec.p2)
LOOP
v_object_name :=
'SEGMENT: ' || rec_obj.segment_name || ' PART: ' ||
rec_obj.partition_name;
END LOOP;
END IF;

/* EVENT: free buffer waits */
IF rec.event = 'free buffer waits'
THEN
NULL;-- capture sql
END IF;

/* EVENT: library cache pin */
IF rec.event = 'library cache pin'
THEN
/* get name of object that the pin is for */
SELECT kglnaobj
INTO v_object_name
FROM sys.x_$kglob
WHERE inst_id = USERENV('instance')
AND kglhdadr = rec.p1raw;
END IF;

SELECT seq_wer_id.nextval
INTO v_wer_id
FROM dual;

/* INSERT current_event data into WAIT_EVENTS_REPOSITORY */
INSERT INTO wait_events_repository
(
wer_id,
sid,
seq#,
event,
p1text,
p1,
p1raw,
p2text,
p2,
p2raw,
p3text,
p3,
p3raw,
wait_time,
seconds_in_wait,
state,
sql_hash_value,
serial#,
logon_time,
object_name,
sampling_date
)
VALUES(
v_wer_id,
rec.sid,
rec.seq#,
rec.event,
rec.p1text,
rec.p1,
rec.p1raw,
rec.p2text,
rec.p2,
rec.p2raw,
rec.p3text,
rec.p3,
rec.p3raw,
rec.wait_time,
rec.seconds_in_wait,
rec.state,
rec.sql_hash_value,
rec.serial#,
rec.logon_time,
v_object_name,
SYSDATE
);

/* capture SQL */
blnrtn :=
capture_sql(
v_wer_id, rec.sql_hash_value, rec.event, rec.machine,
rec.module, NULL
);
/* enqueue event? get blocking sql as well */
blnrtn :=
capture_sql(
v_wer_id, v_blocking_hash_value, rec.event, rec.machine,
rec.module, 'BLOCKER'
);
/*
blnrtn :=
capture_blocking_sql (
v_wer_id
,v_blocking_hash_value
,rec.event
,rec.machine
,rec.module
);
*/
/* reset variables */
v_object_name := NULL;
v_subobject_name := NULL;
END LOOP;/* rec: current_event */

COMMIT;
EXCEPTION
WHEN OTHERS
THEN
raise_application_error(-20001, SQLERRM);
END dc;

FUNCTION capture_sql(
in_wer_id IN NUMBER,
in_hash_value IN v$session.sql_hash_value%TYPE,
in_event IN v$session_wait.event%TYPE,
in_machine IN v$session.machine%TYPE,
in_module IN v$session.module%TYPE,
in_mode IN VARCHAR2 DEFAULT NULL
)
RETURN BOOLEAN
IS
CURSOR extract_sql(
in_hash_value v$session.sql_hash_value%TYPE
)
IS
SELECT st.hash_value, st.address, st.command_type, st.piece,
st.sql_text, sa.disk_reads, sa.buffer_gets
FROM v$sqltext st, v$sqlarea sa
WHERE st.hash_value = in_hash_value
AND st.hash_value = sa.hash_value
ORDER BY st.piece;
BEGIN
FOR r IN extract_sql(in_hash_value)
LOOP
IF in_mode = 'BLOCKER'
THEN
INSERT INTO blocker_repository
(
wer_id,
sql_id,
address,
hash_value,
command_type,
piece,
sql_text,
disk_reads,
buffer_gets,
osuser,
machine,
module
)
VALUES(
in_wer_id,
seq_sql_stmt_id.nextval,
r.address,
r.hash_value,
r.command_type,
r.piece,
r.sql_text,
r.disk_reads,
r.buffer_gets,
in_event,
in_machine,
in_module
);
ELSE
INSERT INTO sql_stmt_repository
(
wer_id,
sql_id,
address,
hash_value,
command_type,
piece,
sql_text,
disk_reads,
buffer_gets,
osuser,
machine,
module
)
VALUES(
in_wer_id,
seq_sql_stmt_id.nextval,
r.address,
r.hash_value,
r.command_type,
r.piece,
r.sql_text,
r.disk_reads,
r.buffer_gets,
in_event,
in_machine,
in_module
);
END IF;
END LOOP;

COMMIT;
RETURN TRUE;
EXCEPTION
WHEN OTHERS
THEN
raise_application_error(-20001, SQLERRM);
RETURN FALSE;
END capture_sql;
END;
/
CREATE TABLE HT4.WAIT_EVENTS_REPOSITORY
(WER_ID NUMBER
,SID NUMBER
,SEQ# NUMBER
,EVENT VARCHAR2(64)
,P1TEXT VARCHAR2(64)
,P1 NUMBER
,P1RAW RAW(4)
,P2TEXT VARCHAR2(64)
,P2 NUMBER
,P2RAW RAW(4)
,P3TEXT VARCHAR2(64)
,P3 NUMBER
,P3RAW RAW(4)
,WAIT_TIME NUMBER
,SECONDS_IN_WAIT NUMBER
,STATE VARCHAR2(19)
,SQL_HASH_VALUE NUMBER
,SERIAL# NUMBER
,LOGON_TIME DATE
,OBJECT_NAME VARCHAR2(1000)
,SAMPLING_DATE DATE
)
/
CREATE TABLE HT4.WAIT_EVENT_PARAMS
(EVENT VARCHAR2(64)
,P1TEXT VARCHAR2(100)
,P2TEXT VARCHAR2(100)
,P3TEXT VARCHAR2(100)
)
/
/* INSERTS FOR ABOVE TABLE */
insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('buffer busy waits', 'Absolute file number where data block resides', 'actual block number', 'reason for the wait')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('control file parallel write', 'Number of control files the server process is writing to', 'Total number of blocks to write to the control files', 'Number of I/O requests')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('direct path write', 'Absolute file number to write to', 'Starting block number to write from', 'Number of blocks to write')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('db file parallel read', 'Number of files to read from', 'Total number of blocks to read', 'Total number of I/O requests (same as P2)')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('db file parallel write', 'Number of files to write to', 'Total number of blocks to write', 'Total number of I/O requests (same as P2)')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('db file scattered read', 'File number to read blocks from', 'Starting block number to begin reading', 'Number of blocks to read')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('db file sequential read', 'File number to read the data block from', 'Starting block number to read', '1 in most cases, but for temporary segments can be more than 1')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('db file single write', 'File number to write to', 'Starting block number to write to', 'The number of blocks to write, typically 1')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('direct path read', 'Absolute file number to read from', 'Starting block number to read from', 'Number of blocks to read')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('enqueue', 'Enqueue name and mode requested by the waiting process', 'Resource identifier ID1 for the requested lock, same as V$LOCK.ID1', 'Resource identifier ID2 for the requested lock, same as V$LOCK.ID2')

/


insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('latch free', 'Address of the latch for which the process is waiting', 'Number of the latch, same as V$LATCHNAME.LATCH#', 'Number of tries; a counter showing the number of attempts the process made to acquire the latch')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('log buffer space', 'N/A', 'N/A', 'N/A')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('log file parallel write', 'Number of logs to write to', 'Number of OS blocks to write to', 'Number of I/O requests')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('log file sequential read', 'Relative sequence number of the redo log file within the redo log group', 'Block number to start reading from', 'Number of OS blocks to read starting from the P2 value')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('log file switch (archiving needed)', 'N/A', 'N/A', 'N/A')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('log file switch (checkpoint incomplete)', 'N/A', 'N/A', 'N/A')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('log file switch completion', 'N/A', 'N/A', 'N/A')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('log file sync', 'The number of the buffer in the log buffer that needs to be synchronized', 'Not Used', 'Not Used')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('SQL*Net message from client', 'ASCII value showing what type of network driver is in use by the client connections; bequeath, TCP', 'The number of bytes received by the session from the client', 'Not used')

/

insert into WAIT_EVENT_PARAMS
(EVENT, P1TEXT, P2TEXT, P3TEXT)
VALUES ('SQL*Net message to client', 'ASCII value showing what type of network driver is in use by the client connections; bequeath, TCP', 'Number of bytes sent to client', 'Not Used')

/
CREATE TABLE HT4.SQL_STMT_REPOSITORY
(ADDRESS RAW(4)
,HASH_VALUE NUMBER
,COMMAND_TYPE NUMBER
,PIECE NUMBER
,SQL_TEXT VARCHAR2(64)
,DISK_READS NUMBER
,BUFFER_GETS NUMBER
,OSUSER VARCHAR2(30)
,MACHINE VARCHAR2(64)
,MODULE VARCHAR2(48)
,SQL_ID NUMBER NOT NULL
,WER_ID NUMBER
,PRIMARY KEY (SQL_ID)
)
/
CREATE TABLE HT4.BLOCKER_REPOSITORY
(ADDRESS RAW(4)
,HASH_VALUE NUMBER
,COMMAND_TYPE NUMBER
,PIECE NUMBER
,SQL_TEXT VARCHAR2(64)
,DISK_READS NUMBER
,BUFFER_GETS NUMBER
,OSUSER VARCHAR2(30)
,MACHINE VARCHAR2(64)
,MODULE VARCHAR2(48)
,SQL_ID NUMBER NOT NULL
,WER_ID NUMBER
,PRIMARY KEY (SQL_ID)
)
/
The goal of this code is to record wait events for analysis during slower periods. It is a self-made Package that I developed while reading the aformentioned book.

Now I set up a job to run this Package procedure call as DC_COLLECTOR.DC; with an interval of 1 minute. The OWNER of this Package and the LOG_USER of the Job is HT4. My problem is that when the job runs, it does not seem to collect any data into my repository tables (it's an active system and it should at worst encounter some latch free or db file sequential read waits occasionally). If I run it from SQL* Plus, it does record rows in my repository tables.

Any ideas?

Excellent answers as always from you...thanks.

Tom Kyte
August 05, 2005 - 2:20 pm UTC

that's alot of code. can you shrink it down to just the single sql statement that is causing you grief?

oops, one boo boo

Mark, August 05, 2005 - 12:33 pm UTC

DBA_EXTENTS_REP is a copy of DBA_EXTENTS...

Single SQL?

Mark, August 05, 2005 - 4:43 pm UTC

Thats the rub, Tom. The SQL is fine. Its the fact that when I have this Package being executed from a job it appears to do nothing, as it writes no records to my home-built repository. When I do

EXEC DC_COLLECTOR.DC;

I get records written to my repository.

But, when I do (assuming the job# = 23554)

EXEC DBM_JOB.RUN(23554);

It executes fairly quickly and no records are written.

here is a session of what I mean:

16:28:35 TRACE LEVEL 4(BIND) - PHYDB001>exec dbms_job.run(23554);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.97
16:28:42 TRACE LEVEL 4(BIND) - PHYDB001>select count(*) from wer;

COUNT(*)
----------
0

1 row selected.

Elapsed: 00:00:00.78
16:28:50 TRACE LEVEL 4(BIND) - PHYDB001>exec dbms_job.run(23554);

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.00
16:28:57 TRACE LEVEL 4(BIND) - PHYDB001>exec dbms_job.run(23554);

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.31
16:28:59 TRACE LEVEL 4(BIND) - PHYDB001>exec dbms_job.run(23554);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.50
16:29:01 TRACE LEVEL 4(BIND) - PHYDB001>exec dbms_job.run(23554);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.66
16:29:02 TRACE LEVEL 4(BIND) - PHYDB001>select count(*) from wer;

COUNT(*)
----------
0

1 row selected.

Elapsed: 00:00:00.78
16:29:06 TRACE LEVEL 4(BIND) - PHYDB001>exec dc_collector.dc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:31.90
16:29:45 TRACE LEVEL 4(BIND) - PHYDB001>exec dc_collector.dc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:13.66
16:30:24 TRACE LEVEL 4(BIND) - PHYDB001>exec dc_collector.dc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:14.25
16:30:40 TRACE LEVEL 4(BIND) - PHYDB001>select count(*) from wer;

COUNT(*)
----------
4

1 row selected.

Elapsed: 00:00:00.09
16:30:50 TRACE LEVEL 4(BIND) - PHYDB001>exec dbms_job.run(23554);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.19
16:30:59 TRACE LEVEL 4(BIND) - PHYDB001>exec dbms_job.run(23554);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.84
16:31:01 TRACE LEVEL 4(BIND) - PHYDB001>exec dbms_job.run(23554);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.97
16:31:03 TRACE LEVEL 4(BIND) - PHYDB001>exec dbms_job.run(23554);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.72
16:31:04 TRACE LEVEL 4(BIND) - PHYDB001>select count(*) from wer;

COUNT(*)
----------
4

You can easily tell by the elapsed times that the DBMS_JOB call is doing way less than the direct EXEC call.

Baffling to me.

I am trying to put together some good TKPROF to post here.

Thanks!

Tom Kyte
August 05, 2005 - 5:46 pm UTC

right -- but what query (out of the big piece of code) is NOT returning data that you believe SHOULD be returning data?

Lets focus on the *single* sql statement in question (make it small)

Doh!

Mark, August 05, 2005 - 4:51 pm UTC

Ok, I'm an idiot. I figured it out...

This code checks to see if this job is running, and of course it is when i execute it from a job...
BEGIN
SELECT job
INTO v_jobid
FROM user_jobs
WHERE what LIKE '%DC_COLLECTOR%';
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN;
END;

SELECT COUNT(*)
INTO v_stillrunning
FROM dba_jobs_running d
WHERE d.job = v_jobid;

IF v_stillrunning <> 0
THEN
RETURN;
END IF;

[egg on face]

Tom Kyte
August 05, 2005 - 5:47 pm UTC

:)

Long running process

Mark, April 14, 2006 - 10:59 am UTC

Hi Tom,

I have a JOB 'X' that is long running (+40 minutes nightly)and gathers application statistics for an overall macro view of the clients information in our application, called a 'dashboard'. It writes to a dozen or so tables, does some fairly intensive SQL, but occasionally fails with

ORA-01650

errors. Being in a job, it restarts of course and eventually finishes.

The PTB (Powers That Be) do not want to make any changes arcitecturally. Is is reasonable for me to break this job into several smaller, faster running jobs to avoid this occasional error?

Great Site as Usual. Use it every day, and have never come away without learning something new.






Tom Kyte
April 14, 2006 - 12:42 pm UTC

depends - reasonable is in the eye of the beholder.

it will greatly increase the complexity of the job perhaps (to take an existing transaction and SAFELY and CORRECTLY break it into many smaller transactions). You are talking about an entire rewrite in many cases.

As opposed to adding a bit of disk - which is not an "architecture" change. In fact, what YOU are suggesting is an architecture change (rewrite code, re-architect code). When they are refusing is a simple "we undersized a resource, let's fix it"

Reasonable

Mark, April 20, 2006 - 4:42 pm UTC

We are squeezed for disk space in the short-term I am told, so no changes are going to be made there, beyond my control.

Breaking it up is 'no big deal' because it is really a bunch of small tasks rolled into one procedure.

Thanks and great as usual.


dba_jobs_running is very slow

Sam, July 14, 2006 - 12:13 pm UTC

select * from dba_jobs_running take 1.5min



Tom Kyte
July 14, 2006 - 1:05 pm UTC

"trace it" and 'autotrace it' and compare the reality (the trace) with the guess (autotrace traceonly explain)

maybe you have stale statistics on your SYS owned tables.
maybe you have missing stats.
maybe you are using the RBO with it.

maybe your X$ tables are really large.

insufficient data to really say - the view itself is rather simple:


select v.SID, v.id2 JOB, j.FAILURES,
LAST_DATE, substr(to_char(last_date,'HH24:MI:SS'),1,8) LAST_SEC,
THIS_DATE, substr(to_char(this_date,'HH24:MI:SS'),1,8) THIS_SEC,
j.field1 INSTANCE
from sys.job$ j, v$lock v
where v.type = 'JQ' and j.job (+)= v.id2


how do queries against your v$lock go? could be slow on a very busy large system.

dba_jobs

saradha, September 13, 2006 - 11:48 am UTC

I have a job of updating all the records in the development database from the production. for simpler explanation i will take dept, emp table. I have to update all the dept records and emp records by transferring everything into a table with object types.

declare
CURSOR c1 is select deptno from temp_collection;
l_date date := to_date('03-DEC-81');
begin
insert into temp_collection SELECT deptno,dname,loc,
cast( multiset( select empno,ename,job,mgr,hiredate,sal,comm,deptno,try
from emp
where emp.deptno = dept.deptno and emp.hiredate >= l_date ) as emp_tab_typ ) emps
FROM dept;
for rec in c1 loop
MERGE INTO dept_dump et
USING (SELECT deptno, dname, loc from temp_collection) es
ON (et.deptno = es.deptno)
WHEN MATCHED THEN
UPDATE
SET et.dname = es.dname
, et.loc = es.loc
WHEN NOT MATCHED THEN
INSERT (et.deptno,et.dname,et.loc)
VALUES (es.deptno,es.dname,es.loc);

MERGE INTO emp_dump et
USING ( select b.empno , b.ename,b.job,b.mgr,b.hiredate,b.sal,b.comm,b.deptno,b.try
from THE(select emp from temp_collection where deptno = rec.deptno) b ) es
ON ( et.empno = es.empno and et.deptno = es.deptno)
WHEN MATCHED THEN
UPDATE
SET et.ename = es.ename
, et.sal = es.sal
, et.mgr = es.mgr
WHEN NOT MATCHED THEN
INSERT
( et.empno, et.ename, et.sal, et.mgr, et.deptno,et.hiredate )
VALUES
( es.empno, es.ename, es.sal, es.mgr, es.deptno, es.hiredate );
end loop;
end;

I should run this as a job. I need to get the last run date from the dba_jobs. so that i will select only those records after the date the job was run last. How do i get the date into picture in this program?

Thanks in advance.

Tom Kyte
September 13, 2006 - 3:04 pm UTC

why would you take this approach.

can we change the question to

how should I sync up development with production?

because I'm not a fan of your current approach.

strange

Sean, October 26, 2006 - 11:30 am UTC

I had set job using dbms_job to exec the procedure every 5 min
procedure ENQUEUE_LOCK_rcd
as
begin
insert into ENQUEUE_LOCK_tab
select t.*, sysdate from (
select a.sql_text, a.module,c.machine, a.first_load_time, d.*
from v$sql a, v$session c, v$lock d
where
c.sid = d.sid
and c.sql_address = a.address
---and d.request > 0 or d.block>0
) t
where t.request > 0 or block>0
;
commit
;
end
;

it had been running a while, then i decided not using it.

so i removed the job by dbms_job.remove.

But we still see the job runs in the db.
i tried the bounce of the db and truncated the table ENQUEUE_LOCK_tab, but no help.

we are on 9.2.0.7




Tom Kyte
October 26, 2006 - 12:26 pm UTC

then someone else had it scheduled as well. look at dba_jobs.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library