I defined a job to run from Tuesday to Sundays every 5 min. from 9:00 am to 22:00 pm
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'GET_INVOICES_JOB',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN LOPES.GET_INVOICES; END;',
repeat_interval =>'FREQ=MINUTELY; INTERVAL=5; BYHOUR=9,22; BYDAY=TUE,WED,THU,FRI,SAT,SUN',
enabled => TRUE,
comments => 'GET_INVOICES');
END;
/
But the job does not run cheking
SELECT *
FROM USER_SCHEDULER_JOB_RUN_DETAILS
ORDER BY LOG_DATE DESC
Checking the Job it seems to be OK:
and running the job manually it execute the procedure but only once not every 5 minutes
This is one of the most common Scheduler questions asked.
Here we list some of the common problems and their solutions.
1) job_queue_processes may be too low (this is the most common problem)
The value of job_queue_processes limits the total number of dbms_scheduler
and dbms_job jobs that can be running at a given time.
To check whether this is the case check the current value of
job_queue_processes with
SQL> select value from v$parameter where name='job_queue_processes';
Then check the number of running jobs
SQL> select count() from dba_scheduler_running_jobs;
SQL> select count() from dba_jobs_running;
If this is the problem you can increase the parameter using
SQL> alter system set job_queue_processes=1000;
2) max_job_slave_processes may be too low
If this parameter is not NULL then it limits how many dbms_scheduler jobs can
be running at a time. To check whether this is the problem, check the current
value using
SQL> select value from dba_scheduler_global_attribute
where attribute_name='MAX_JOB_SLAVE_PROCESSES';
Then check the number of running jobs
SQL> select count(*) from dba_scheduler_running_jobs;
If this is the problem you can increase the number or just NULL it out using
SQL> exec dbms_scheduler.set_scheduler_attribute('max_job_slave_processes',null)
3) sessions may be too low
This parameter limits the number of sessions at any time. Every Scheduler job
requires 2 sessions. To check whether this is the problem, check the current
valule using
SQL> select value from v$parameter where name='sessions';
Then check the current number of sessions using
SQL> select count(*) from v$session ;
If the numbers are too close you can increase the maximum using
SQL> alter system set job_queue_processes=200;
4) Have you recently applied a timezone update patch or upgraded the database
to a version with newer timezone information ? If you skipped any steps when
updating the timezone information, jobs may not run. To check whether this
is the case try doing
SQL> select * from sys.scheduler$_job;
and
SQL> select * from sys.scheduler$_window;
and make sure they finish without errors.
If it throws a timezone warning, reapply the upgrade or
timezone patch making sure to follow all the steps.
5) Is the database running in restricted mode ?
If the database is running in restricted mode then no jobs will run (unless
you are using 11g and use the ALLOW_RUNS_IN_RESTRICTED_MODE attribute).
To check this use
SQL> select logins from v$instance ;
If logins is restricted you can disable the restricted mode using
SQL> ALTER SYSTEM DISABLE RESTRICTED SESSION;
6) Is the job scheduled to run on an instance which is down ?
You can check this by seeing whether instance_id is set for the job (check the dba_scheduler_jobs view), and if so you should check whether that instance is up.
7) Is the job scheduled to run on a service which has not been started on any instances ?
You can check this by checking what job_class a job points to and then checking whether that class points to a service. If it does, make sure the service has been started on at least one running instance. You can start a service on an instance using dbms_service.start_service.
8) Is the Resource Manager in effect with a restrictive resource plan ?
If a restrictive resource plan is in effect, scheduler jobs may not have sufficient resources allocated so they may not run. You can check what resource plan is in effect by doing
SQL> select name from V$RSRC_PLAN ;
If no plan is in effect or the plan in effect is INTERNAL_PLAN then the resource manager is not in effect. If the resource manager is in effect you can disable it by doing
SQL>alter system set resource_manager_plan = '';
9) Has the Scheduler been disabled ? This is not a supported action
but it is possible that someone has done it anyway. To check this do
SQL> select value from dba_scheduler_global_attribute where attribute_name='SCHEDULER_DISABLED'
If this query returns TRUE then you can fix this using
SQL> exec dbms_scheduler.set_scheduler_attribute('scheduler_disabled','false');
Reasons why jobs may run late
1) The first thing to check is the timezone that the job is scheduled with
SQL> select owner, job_name, next_run_date from dba_scheduler_jobs ;
If the jobs are in the wrong timezone they may not run at the expected
time. If the next_run_date is using an absolute timezone offset (like
+08:00) instead of a named timezone (like US/PACIFIC) then the jobs may not
run as expected if daylight savings is in effect - they may run an hour
early or late.
2) It may be that at the time the job was scheduled to run, one of the several
limits above may have been temporarily reached causing the job to be delayed.
Check if the limits above are high enough and if possible check them during
the time that the job is being delayed.
3) One possible reason that one of the above limits may be hit is that a
maintenance window may have come into effect. Maintenance windows are Oracle
Scheduler windows that belong to the window group named
MAINTENANCE_WINDOW_GROUP. During a scheduled maintenance window, several
maintenance tasks are run using jobs. This may cause one of the limits listed
above to be hit and user jobs to be delayed. See the admin guide for more info
about this (chapter 24).
To get a list of maintenance windows use
SQL> select * from dba_scheduler_wingroup_members;
To see when the windows run use
SQL> select * from dba_scheduler_windows;
To fix this you can either increase the limits or reschedule the maintenance
windows to run at more convenient times.
Diagnosing other Problems
If none of this works, here are some further steps you can take to try to
figure out what is going on.
1) Check whether there are any errors in the alert log. If the database is
having trouble allocating memory or has run out of disk space or any other
catastrophic errors have occurred, you should resolve those first. You can
find the location of the alert log by using
SQL> select value from v$parameter where name = 'background_dump_dest';
The alert log will be in this directory with a name starting with "alert".
2) Check whether if a job coordinator trace file and if it does, check if it
contains any errors. If this exists, it will be located in the
'background_dump_dest' directory which you can find as above and will look
something like SID-cjq0_nnnn.trc . If there are any errors here they may
hint at why jobs are not running.
3) If either of the above indicates that the SYSAUX tablespace (where the scheduler stores its logging tables) is full, you can use the dbms_scheduler.purge_log procedure to clear out old log entries.
4) See if there is a window currently open. If there is, you can try closing it to see if that helps .
SQL> select * from DBA_SCHEDULER_GLOBAL_ATTRIBUTE where
attribute_name='CURRENT_OPEN_WINDOW';
SQL> exec DBMS_SCHEDULER.close_window ('WEEKNIGHT_WINDOW');
5)try running a simple run-once job and see if it runs
SQL>begin
dbms_scheduler.create_job (
job_name => 'test_job',
job_type => 'plsql_block',
job_action => 'null;',
enabled => true);
end;
/
SQL> -- wait a while
SQL> select * from user_scheduler_job_run_details where job_name='TEST_JOB';
6) If a simple run-once job doesn't run, you can try restarting the scheduler as follows.
SQL> exec dbms_scheduler.set_scheduler_attribute('SCHEDULER_DISABLED', 'TRUE');
SQL> alter system set job_queue_processes=0;
SQL> exec dbms_ijob.set_enabled(FALSE);
SQL>
SQL> alter system flush shared_pool;
SQL> alter system flush shared_pool;
SQL>
SQL> exec dbms_ijob.set_enabled(TRUE);
SQL> alter system set job_queue_processes=99;
SQL> exec dbms_scheduler.set_scheduler_attribute('SCHEDULER_DISABLED', 'FALSE');
In a Multitenant environment the container also has to have the right value for the job_queue_processes.
Related
Log changing by using trigger. I know about old and new in trigger, where you can find out old row of DML and new. But I don't know how to log what user changes in object.
There's no way I'm aware of to track old code in Oracle. You would need to use an external tool like Git to properly apply version control and catalog your code. If you want to track who changes code in the database, then use auditing; that is the preferred method of tracking DDL changes. Using USER_OBJECTS will only show you the latest change, not a complete history, so it is easy to miss things. Flashback generally has a very limited time span to allow you to look back, so that's not ideal for your purposes either.
Auditing can capture most if not all session parameters, include client OS user, database proxy user, and others so that you can identify the true user even when a common database account/schema is being used by several developers.
I don't know how to log what user changes in object.
You said it. It is user, a function that returns current session user.
SQL> connect scott/tiger
Connected.
SQL>
SQL> select user from dual;
USER
------------------------------
SCOTT
SQL>
Therefore, just include user into your trigger and that should do.
Based on comment you posted, it looks you're looking for user who modified the procedure code (not who modified data via the procedure).
In that case, that's the procedure's owner (unless someone else has been granted ALTER ANY PROCEDURE system privilege).
If many people log into that schema and can modify procedure's code, then: think whether that's a correct approach to the database. There should be a development database, with versioning enabled (consider Git or Subversion, for example) which then collects data about what's been changed in code, who did it and when.
As of production database: developers shouldn't be allowed to access it. Let the DBA apply changes to objects.
If you query user_objects, there's information of the last DDL time.
SQL> create or replace procedure p_test is
2 begin
3 null;
4 end;
5 /
Procedure created.
SQL> select created, last_ddl_time from user_objects where object_name = 'P_TEST';
CREATED LAST_DDL_TIME
------------------- -------------------
03.10.2021 20:59:53 03.10.2021 20:59:53
SQL> alter procedure p_test compile;
Procedure altered.
SQL> select created, last_ddl_time from user_objects where object_name = 'P_TEST';
CREATED LAST_DDL_TIME
------------------- -------------------
03.10.2021 20:59:53 03.10.2021 21:00:08
SQL>
Additionally: if you use flashback, you can see how the procedure looked like some time ago, but I'm not sure you can use it for logging purposes.
SQL> connect scott/tiger
Connected.
SQL> create or replace procedure p_test is
2 begin
3 dbms_output.put_line('Hello');
4 end;
5 /
Procedure created.
SQL> connect sys as sysdba
Enter password:
Connected.
SQL> select text from dba_source
2 as of timestamp systimestamp - interval '5' minute
3 where owner = 'SCOTT'
4 and name = 'P_TEST';
TEXT
--------------------------------------------------------------------------------
procedure p_test is
begin
null;
end;
SQL>
As others answered - the internally compiled code in oracle is not versioned. The versioning of code is something that you need to implement in the development team. There are a couple of best practices you can follow
When working on code, take the latest version from source code control - that should be the source of truth. If someone hasn't checked in - then his/her code is lost.
Whenever a code change is made, the developer immediately checks in his code. The check-in is the indicator that code has changed.
use comments in the code to indicate who made a change. In our code we have a comments section in the package spec with a single line per change.
You should also look at using a tool like liquibase to track changes in your objects
Oracle version 12.1.0.2.0.
Toad version 12.1.0.22
I have a Table_A with 2 columns (A NUMBER, B NUMBER). Table_A is a new object created for a datafix. No application live objects are referring this.
Due to logic issue, an insert statement initiated a transaction to insert billions of record into the table_A. I found it mid way, killed the Oracle session with help of DBAs. Now the session is killed and I do not see them using session browser in Toad. It took almost 4 hours for the killed session to be removed from session browser. The killed session was available in session browser for the 4 hours with Status as Killed. I believe it must be rolling back the data.
Current Problem:
If I select (without hint) Table_A from my Oracle user account I'm either getting below ora error or the select runs forever (it kept running for more than 30 minutes, so I stopped the execution)
ORA-02395: exceeded call limit on IO usage
If I select with hint, it returns 0 rows.
Select /*+parallel(4)*/ *
from table_A;
Question:
Whether Killed session have any issues and running some IO in background ? I have no clue why the select statement (without hint) is running longer to return 0 rows. As this happened in prod system, I'm worried if any background process would cause any issue in coming days.
Apologies, I do not have DBA privileges to check locks or background running processed. If I missed to provide any additional info, please let me know. Thank you in advance for your time in responding back.
AS this happened in Production system, I do not have access to much of oracle v$ or metadata tables. I tried using session browser to find locks, background process but none helped
select *
from table_A;
I expect it to return 0 rows without a delay.
I am using following query to enable the oracle job:
exec dbms_scheduler.disable('23');
where '23' is my Job id. But this seems to be not working for id. I read that, job name should be given in place of '23'. But my job does not have name. It has only Id.
So how to enable it using job Id? any other command to execute?
older DBMS_JOBS had IDs, not scheduler ones. ie you may want this(if your seeing your job in DBA_JOBS view):
begin
dbms_job.broken(23, true);
commit;
end;
/
I'm going to make up some sql here. What I want is something like the following:
select ... for update priority 2; // Session 2
So when I run in another session
select ... for update priority 1; // Session 1
It immediately returns, and throws an error in session 2 (and hence does a rollback), and locks the row in session 1.
Then, whilst session 1 holds the lock, running the following in session 2.
select ... for update priority 2; // Session 2
Will wait until session 1 releases the lock.
How could I implement such a scheme, as the priority x is just something I've made up. I only need something that can do two priority levels.
Also, I'm happy to hide all my logic in PL/SQL procedures, I don't need this to work for generic SQL statements.
I'm using Oracle 10g if that makes any difference.
I'm not aware of a way to interrupt an atomic process in Oracle like you're suggesting. I think the only thing you could do would be to programmaticaly break down your larger processes into smaller ones and poll some type of sentinel table. So instead of doing a single update for 1 million rows perhaps you could write a proc that would update 1k, check a jobs table (or something similar) to see if there's a higher priority process running, and if a higher priority process is running, to pause its own execution through a wait loop. This is the only thing I can think that would keep your session alive during this process.
If you truly want to abort the progress of your currently running, lower priority thread and losing your session is acceptable, then I would suggest a jobs table again that registered the SQL that was being run and the session ID that it is run on. If you run a higher priority statement it should again check the jobs table and then issue a kill command to the low priority session (http://www.oracle-base.com/articles/misc/KillingOracleSessions.php) along with inserting a record into the jobs table to note the fact that it was killed. When a higher-priority process finishes it could check the jobs table to see if it was responsible for killing anything and if so, reissue it.
That's what resource manager was implemented for.
If I execute a simple select statement in pl/sql developer against a database table, I get a standard set of results back as I would expect.
Recently, I pasted a query from a stored procedure that happened to select from a view, and noticed that a transaction was seemingly left open. This was appraent by the rollback and commit options were available in PL/SQL developer.
A poll of other developers revealed that this seems to affect some but not others, which lead me to suspect PL/SQL Developer settings.
Why on earth would this be the case? The view itelf has a DBLink to another database, but I wouldn't expect this to have any effect.
Any thoughts?
Contrary to your expectation, it looks like the database link is the source of the open transaction. I've noticed behaviour like this before when running SELECT queries on remote tables in PL/SQL Developer.
To quote Tom Kyte (source):
distributed stuff starts a transaction "just in case".
EDIT: 'Any SQL statement starts a transaction in Oracle'? No, it does not, and here's a demonstration of it. This demonstration uses the data dictionary view V$TRANSACTION, which lists the active transactions. This is all running on my local Oracle XE database, which has no users other than me connected to it.
We'll use the following table during this demonstration. It contains only a single column:
SQL> desc test;
Name Null? Type
----------------------------------------- -------- ----------------------------
A NUMBER(38)
SQL> select count(*) from v$transaction;
COUNT(1)
----------
0
No active transactions at the moment. Let's run a SQL query against this table:
SQL> select * from test;
A
----------
2
SQL> select count(*) from v$transaction;
COUNT(1)
----------
0
Still no active transactions. Now let's do something that will start a transaction:
SQL> insert into test values (1);
1 row created.
SQL> select count(*) from v$transaction;
COUNT(1)
----------
1
As expected, we now have an active transaction.
SQL> commit;
Commit complete.
SQL> select count(*) from v$transaction;
COUNT(1)
----------
0
After committing the transaction, it's no longer active.
Now, let's create a database link. I'm using Oracle XE, and the following creates a database link from my Oracle XE instance back to itself:
SQL> create database link loopback_xe connect to user identified by password using 'XE';
Database link created.
Now let's see what happens when we select from the table over the database link:
SQL> select count(*) from v$transaction;
COUNT(1)
----------
0
SQL> select * from test#loopback_xe;
A
----------
2
1
SQL> select count(*) from v$transaction;
COUNT(1)
----------
1
As you can see, simply selecting from a remote table opens a transaction.
I'm not sure exactly what there is to commit or rollback here, but I have to admit to not knowing the ins and outs of distributed transactions, within which the answer probably lies.
Any SQL Statement starts a transaction in Oracle.
From the manual:
A transaction begins with the first executable SQL statement. A transaction ends when it is committed or rolled back, either explicitly with a COMMIT or ROLLBACK statement or implicitly when a DDL statement is issued. [...] An executable SQL statement is a SQL statement that generates calls to an instance, including DML and DDL statements
Most probably those who are not seing this are running in auto-commit mode where the transaction started by a statement is immediately committed after the statement has finished.
Others have claimed that a SELECT is not DML, but again the manual clearly states:
Data manipulation language (DML) statements query or manipulate data in existing schema objects. They enable you to:
* Retrieve or fetch data from one or more tables or views (SELECT)
* Add new rows of data into a table or view (INSERT)
[...]
You absolutely cannot open a transaction strictly with a normal query. You may open one across a database link. The guy who posted a link to the doctors either deliberately or utterly carelessly left out the 2nd sentence.
"A transaction in Oracle Database begins when the first executable SQL
statement is encountered. An executable SQL statement is a SQL
statement that generates calls to an instance, including DML and DDL
statements."
SELECT is neither a DML nor a DDL. It is also TRIVIAL to actually test this. I don't want to come off like a troll here, but its really annoying when people just throw out answers on a forum to try to get points and the answers are complete garbage.
Read the rest of the doc and TEST IT FIRST.
login to a session
run a select
see if you have an open transaction by joining v$Session (for your session) to v$transaction.
If a record comes back, you have a transaction. If not, you don't.
Note, according to the Oracle 11g Admin Guide, if you do a plain old SELECT across a database link you will start a transaction, which needs to be committed (or rolled back).
Select is a part of DML only but lock is not acquired, A row lock is fetched upon insert/update/delete/ select for update. -Ross is right.
https://docs.oracle.com/cd/E11882_01/server.112/e41084/ap_locks001.htm#SQLRF55502
ROW Lock Table lock
SELECT ... FROM table... ----- None
INSERT INTO table ... Yes SX
Same with update delete and select for update.
TLDR : On select from remote database you also create session and connection for remote DB. That session and connection persists as long as local user session. As you can guess this can lead to some problems with keeping up with session and connections.
SO ALWAYS DO A COMMIT :
SELECT * FROM emp#sales;
COMMIT;
I like a long read section :
This was bugging me also so much why there is an transaction on selects from db_links
and decided to finally end this so from oracle documentation :
Oracle® Database Administrator's Guide
11g Release 2 (11.2)
https://docs.oracle.com/html/E25494_01/ds_appdev002.htm
Controlling Connections Established by Database Links
When a global object name is referenced in a SQL statement or remote procedure call, database links establish a connection to a session in the remote database on behalf of the local user. The remote connection and session are only created if the connection has not already been established previously for the local user session.
The connections and sessions established to remote databases persist for the duration of the local user's session, unless the application or user explicitly terminates them. Note that when you issue a SELECT statement across a database link, a transaction lock is placed on the undo segments. To rerelease the segment, you must issue a COMMIT or ROLLBACK statement.
Terminating remote connections established using database links is useful for disconnecting high cost connections that are no longer required by the application. You can terminate a remote connection and session using the ALTER SESSION statement with the CLOSE DATABASE LINK clause. For example, assume you issue the following transactions:
SELECT * FROM emp#sales;
COMMIT;
The following statement terminates the session in the remote database pointed to by the sales database link:
ALTER SESSION CLOSE DATABASE LINK sales;
To close a database link connection in your user session, you must have the ALTER SESSION system privilege.
Note:
Before closing a database link, first close all cursors that use the link and then end your current transaction if it uses the link.
See Also:
Oracle Database SQL Language Reference for more information about the ALTER SESSION statement