Q: | |
25-1. | You need DBMS_JOB to schedule and execute PL/SQL procedures at predefined times or at regular intervals, such as routine maintenance procedures or developer batch jobs. |
Q: | |
25-2. | The three INIT.ORA parameters that affect DBMS_JOB are: - JOB_QUEUE_INTERVAL
Specifies (in seconds) how often the Oracle SNP process “wakes up” to check the job queue. Too small an interval (or too many queue processes) decreases server performance; too large an interval can cause the jobs to fall behind schedule. The recommended value for most cases is 60 seconds. - JOB_QUEUE_PROCESSES
Specifies the number of concurrent SNP background processes (i.e., how many jobs can execute in parallel). This value can range from 0 (the default) to 36. A value of 1 or 2 is usually enough for a small number of jobs. - JOB_QUEUE_KEEP_CONNECTIONS
Specifies whether database connections established by the background processes are held open during “sleep periods” (no jobs running). This value may be either TRUE, in which case the process keeps its connection, or FALSE (the default), in which case the process closes the connection and reestablishes a new one the next time it runs. While a TRUE value yields better performance, it can also interfere with the ability to shut down the database.
|
Q: | |
25-3. | Since only one concurrent process is allowed, the second job must wait until the first job is complete. |
Q: | |
25-4. | No, it’s not possible. Every started job establishes a lock in the V$LOCK table to prevent other processes from reexecuting the job. |
Q: | |
25-5. | DBMS_JOB has two procedures to submit a job into the queue: SUBMIT and ISUBMIT. Both procedures share the following parameters: - job
A unique identifier for a particular job. You use this number, which uniquely identifies each job, to perform any operations with the job, such as querying Oracle’s data dictionary about various jobs, updating the job execution interval, etc. - what
The PL/SQL block executes when the job runs (a stored procedure call is assumed to be enclosed within a BEGIN-END block). - next_date
The next date the job will execute. - interval
A date function that determines how to compute the next execution date. After a job executes successfully, the value of this function becomes the new next_date. - no_parse
A BOOLEAN flag that specifies whether you want to parse the job’s what parameter immediately (indicated by a FALSE) or whether to wait until the first execution (indicated by a TRUE).
|
Q: | |
25-6. | SUBMIT assigns a unique ID for the job automatically from the sequence SYS.JOBSEQ, and returns this number in the OUT parameter job. ISUBMIT allows you to supply your own job ID with the IN parameter job. When using ISUBMIT, you’re responsible for guaranteeing a unique ID. Otherwise, you receive the following error: ORA-00001: unique constraint (SYS.I_JOB_JOB) violated |
Q: | |
25-7. | Even though Oracle documentation states that it is not necessary, you should always issue a COMMIT after each call to SUBMIT or ISUBMIT: BEGIN
DBMS_JOB.ISUBMIT ( 33, 'calc_totals;', SYSDATE, 'SYSDATE + 1'),
COMMIT;
END;
/ |
Q: | |
25-8. | The job never executes because the next_date parameter is set to NULL, which causes DBMS_JOB to set the next execution date to January 1, 4000 (effectively preventing the execution of the job). It allows you to submit a job, but does not yet submit it for execution. |
Q: | |
25-9. | You must remember to end your stored procedure call or anonymous block with a semicolon. Oracle doesn’t do it for you. DBMS_JOB.ISUBMIT (job => 33,
what => 'foo;',
next_date => NULL,
interval => 'SYSDATE + 1'), |
Q: | |
25-10. | No; in fact, probably the only thing you can be sure of is it won’t be 1:00 P.M.! To see why, suppose that interval is set to 60 (the default). On average, you’ll have a 30-second delay every time before starting the job, resulting in a 3-hour (30 * 365 / 3600) delay per year! This cumulative shifting (i.e., later and later), or drift, is inherent in interval expressions such as ‘SYSDATE + 1’. To set an exact time, use the TRUNC function and date arithmetic in the INTERVAL parameter to set up the next execution time precisely: DBMS_JOB.ISUBMIT (
job => 33,
what => 'DUMP_USERS;',
next_date => SYSDATE,
interval => 'TRUNC(SYSDATE) + 13/24'
); The TRUNC function truncates the current date to noon, and + 13/24 means “add 13 hours from midnight” (i.e., 1:00 P.M.). Such declarations ensure that the next execution time is close to 1:00 P.M., regardless of the previous execution time. If you want to operate in minutes, not hours, use the formula ‘minutes / (24 * 60)’ to qualify the number of minutes you want to add. |
Q: | |
25-11. | There are two ways to temporarily stop a job (without, of course, deleting it from the queue). The first option is to use the DBMS_JOB.BROKEN procedure to set the broken flag to TRUE for the job, since broken jobs are never run: DBMS_JOB.BROKEN (job => 33, broken => TRUE); To return the job to its normal state, simply set the broken flag back to FALSE. The second method is to change the next_date parameter to some date far in the future using DBMS_JOB.NEXT_DATE: DBMS_JOB.NEXT_DATE (
job => 33,
next_date => TO_DATE ('01.01.3000', 'DD.MM.YYYY')
); Better yet, you can set next_date to NULL, which, as we’ve already seen, will automatically set the next execution date to January 1, 4000: DBMS_JOB.NEXT_DATE (job => 33, next_date => NULL); |
Q: | |
25-12. | Yes, you can use the DBMS_JOB.RUN procedure to run the task. This sets the broken flag to FALSE if execution was successful. So after improving and compiling the foo procedure, all you need to do is to run Job 33: DBMS_JOB.RUN (job => 33);
COMMIT; This way you can both return the job to the job queue and test to make sure it runs. |
Q: | |
25-13. | Submit the job with a NULL value in the interval parameter. For example, if you have a table you want to clear out three days hence, you can use the following call: DBMS_JOB.ISUBMIT (
job => 34,
what => 'delete from CONFIDENTIAL_DOCS;',
next_date => TRUNC (SYSDATE) + 3,
interval => NULL
); |
Q: | |
25-14. | You can use the DBMS_JOB.RUN procedure to force an immediate execution. This should be done with caution, however, as there are a number of possible side effects. For example: Assuming that next_date follows the “SYSDATE + 1” format, rather than a “TRUNC(SYSDATE)+1” format, executing the job manually permanently changes the job’s execution time. For example, if the job was originally submitted to run daily at around 12:00 A.M., and you execute it manually at 1:30 P.M., it runs in the middle of the day from then on. The National Language Support (NLS) settings specified when the job was originally submitted are changed to the settings of the user who reexecuted the job. If the two users have different NLS settings, this can cause problems. The broken flag might change.
|
Q: | |
25-15. | The ALL_JOBS and DBA_JOBS data dictionary views provide you with information about all jobs in the queue. Although these views have a huge number of columns, the most interesting columns are JOB, LAST_DATE (last successful execution), NEXT_DATE (next planned execution), LOG_USER (job owner), BROKEN, INTERVAL, FAILURES (number of unsuccessful executions), and WHAT. The DBA_JOBS_RUNNING view provides information about currently running jobs. |
Q: | |
25-16. | The following script shows the status of all the jobs in the queue: ALTER SESSION SET NLS_DATE_FORMAT = 'HH24:MI DD MON';
SELECT job,
SUBSTR (
DECODE (
broken, 'Y',
'BROKEN', DECODE (
failures,
0, 'OK',
NULL, 'NEW ',
TO_CHAR (failures) || ' FAILURES'
)
),
1,
11
)
status,
SUBSTR (log_user, 1, 15) owner,
last_date,
next_date,
SUBSTR (what, 1, 20) what
FROM dba_jobs
ORDER BY next_date; This script shows NEW in the STATUS column for just-submitted jobs, OK for successful jobs, BROKEN for already broken, and number of failures otherwise. Here is sample output: JOB STATUS OWNER LAST_DATE NEXT_DATE WHAT
--------- ----------- --------------- ------------ ------------ -----
17 OK PLV 19:19 07 MAR 19:20 07 MAR test
33 3 FAILURES PLV 19:26 07 MAR AAA;
2 OK PLV 10:39 07 MAR 01:28 08 MAR begin
36 OK PLV 15:30 07 MAR 15:30 08 MAR NULL;
34 NEW PLV 00:00 10 MAR delete
10000 BROKEN PLV 00:19 05 MAR 00:00 01 JAN update |
Q: | |
25-17. | This script shows the ID of the session where job is running, the username for this session, the job number, and the time the job was started: ALTER SESSION SET NLS_DATE_FORMAT = 'HH24:MI DD MON';
SELECT r.sid,
s.username,
j.job,
r.this_date,
SUBSTR (j.what, 1, 20) what
FROM dba_jobs_running r,
dba_jobs j,
v$session s
WHERE j.job = r.job
AND r.sid = s.sid; |
Q: | |
25-18. | Although doing so would be wonderful, you should not use user-defined functions (in this case, next_business_day) in the interval parameter. Although you can submit such jobs, they don’t execute at the correct times. Consequently, you should use PL/SQL date functions only. |
Q: | |
25-19. | You can use the WHAT, NEXT_DATE, and INTERVAL procedures from the DBMS_JOB package. Each procedure changes the corresponding parameter. Another procedure, CHANGE, can change any or all of the parameters. For example, to change the execution interval for job #33, issue the call: DBMS_JOB.INTERVAL (job => 33, interval => 'TRUNC(SYSDATE) + 7'), Note that you can’t change the job number. |
Q: | |
25-20. | It’s really easy; simply create a PL/SQL block with two commands instead of one: DBMS_JOB.ISUBMIT (
job => 36,
what => ' BEGIN LFF; PRR; END;',
next_date => SYSDATE,
interval => 'SYSDATE + 1'
); |
Q: | |
25-21. | You can make a job jump to the head of the queue by setting its next_date parameter to some date in the past: DBMS_JOB.ISUBMIT (
job => 58,
what => 'URGENT_JOB;',
next_date => TRUNC (SYSDATE) - 1,
interval => NULL
); This works because Oracle selects jobs for execution based on the order of next_date; the new job is fetched first (assuming, of course, you have no jobs with a next_date earlier that what you set your job to). |
Q: | |
25-22. | The first way to remove the job is to use DBMS_JOB.REMOVE: DBMS_JOB.REMOVE (job => 58); The second way is to change the job’s interval parameter to NULL: DBMS_JOB.INTERVAL (job => 58, interval => NULL); Note that in either case, if the job is already running when you issue the command, it is allowed to finish and then is removed from the job queue. Consequently, you can’t use either method to “kill” an abnormal or long-running job. |
Q: | |
25-23. | DBMS_JOB has a special procedure for this purpose: DBMS_JOB.USER_EXPORT. Calling this procedure returns, via a VARCHAR2 OUT parameter, a string consisting of a call to DBMS_JOB.ISUBMIT. You can then execute this string in the other database to recreate the job. Remember that the other database could already have a job with the same number, so you must check this and adjust the job number if necessary. The job number can be adjusted upwards by issuing the following SELECT until it is at an appropriate value: SELECT SYS.JOBSEQ.NEXTVAL FROM dual; |