What is the way to kill an executing procedure? - oracle

I am using Oracle sql developer. I have a procedure involving MINUS statement between two tables (table 1 and table 2). The table 1 has more than a million rows data. In this situation, when I am trying to execute it, it returns nothing but is in executing stage.
Meanwhile, I need to truncate this table data. But, when doing this, I got a resource busy error. How to terminate the executing stored procedure and how to do truncate operation meanwhile?

You do not kill a procedure, you kill a session.
Before killing the session, you might want to know that readers do not block writers and vice-versa. So, if you want to select/project the rows from the table being modified, you could always do it.
Identify the session:
SELECT s.sid,
s.serial#,
p.spid,
s.username,
s.program
FROM v$session s
JOIN v$process p ON p.addr = s.paddr
WHERE s.type != 'BACKGROUND';
Kill the session:
ALTER SYSTEM KILL SESSION 'sid,serial#';
The KILL SESSION command doesn't actually kill the session. It merely asks the session to kill itself. In some situations, like waiting for a reply from a remote database or rolling back transactions, the session will not kill itself immediately and will wait for the current operation to complete. In these cases the session will have a status of "marked for kill". It will then be killed as soon as possible.
In addition to the syntax described above, you can add the IMMEDIATE clause.
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;
This does not affect the work performed by the command, but it returns control back to the current session immediately, rather than waiting for confirmation of the kill.
Read this article for more details.

Related

How does the toggling of the status column in V$session work?

I was wanting to know how does the status column in V$session work. I understand that the column shows if a particular session is active or inactive. I also understand that a session is active when it is executing an sql statement. However, I wanted to know what is the status of a session when a plsql block or a program is being executed.
For eg: I have a plsql procedure like below
PROCEDURE XYZ is
.
.
begin
<SQL statement>
.
.
<some other plsql code>
.
.
<dbms output statements>
.
.
<SQL statement>
.
.
<some other plsql code>
.
.
<dbms output statements>
End XYZ;
I wanted to know that when once the sql statement finishes and the other stuff like other plsql code or dbms output statements are executing, what is the status of the session during that time? is it active or inactive as no sqls are running at that moment.
There is no special rule for executing procedures. If the session is currently waiting on a lock or spinning on some cpu-intensive non-SQL operation that will be reflected in the status regardless of whether the task is executed as part of a procedure or not.
The documentation defines 'ACTIVE' as 'Currently executing SQL', but from a quick test my session remained 'ACTIVE' when waiting on a locked object, waiting on dbms_lock.sleep and incrementing a counter in a loop. I don't know if there is any official list of actions do or don't count as 'ACTIVE', though.
It should switch between ACTIVE and INACTIVE status; from documentation
Status of the session:
ACTIVE - Session currently executing SQL
INACTIVE
KILLED - Session marked to be killed
CACHED - Session temporarily cached for use by Oracle*XA
SNIPED - Session inactive, waiting on the client
Nothing about running PLSQL. But you could however be locking table and objects with PLSQL treatment alone, so you would have your session only waiting for commit instead of being ACTIVE.
edit
However, since you can't call PLSQL out of nothing; PLSQL is called e.g. from sqlplus client... This might count as SQL to Oracle. So the whole procedure would in this case enable the session as ACTIVE.

Oracle: SQL Error: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired [duplicate]

Why am I getting this database error when I update a table?
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
Your table is already locked by some query. For example, you may have executed "select for update" and have not yet committed/rollbacked and fired another select query. Do a commit/rollback before executing your query.
from here ORA-00054: resource busy and acquire with NOWAIT specified
You can also look up the sql,username,machine,port information and get to the actual process which holds the connection
SELECT O.OBJECT_NAME, S.SID, S.SERIAL#, P.SPID, S.PROGRAM,S.USERNAME,
S.MACHINE,S.PORT , S.LOGON_TIME,SQ.SQL_FULLTEXT
FROM V$LOCKED_OBJECT L, DBA_OBJECTS O, V$SESSION S,
V$PROCESS P, V$SQL SQ
WHERE L.OBJECT_ID = O.OBJECT_ID
AND L.SESSION_ID = S.SID AND S.PADDR = P.ADDR
AND S.SQL_ADDRESS = SQ.ADDRESS;
Please Kill Oracle Session
Use below query to check active session info
SELECT
O.OBJECT_NAME,
S.SID,
S.SERIAL#,
P.SPID,
S.PROGRAM,
SQ.SQL_FULLTEXT,
S.LOGON_TIME
FROM
V$LOCKED_OBJECT L,
DBA_OBJECTS O,
V$SESSION S,
V$PROCESS P,
V$SQL SQ
WHERE
L.OBJECT_ID = O.OBJECT_ID
AND L.SESSION_ID = S.SID
AND S.PADDR = P.ADDR
AND S.SQL_ADDRESS = SQ.ADDRESS;
kill like
alter system kill session 'SID,SERIAL#';
(For example, alter system kill session '13,36543';)
Reference
http://abeytom.blogspot.com/2012/08/finding-and-fixing-ora-00054-resource.html
There is a very easy work around for this problem.
If you run a 10046 trace on your session (google this... too much to explain). You will see that before any DDL operation Oracle does the following:
LOCK TABLE 'TABLE_NAME' NO WAIT
So if another session has an open transaction you get an error. So the fix is... drum roll please. Issue your own lock before the DDL and leave out the 'NO WAIT'.
Special Note:
if you are doing splitting/dropping partitions oracle just locks the partition.
-- so yo can just lock the partition subpartition.
So...
The following steps fix the problem.
LOCK TABLE 'TABLE NAME'; -- you will 'wait' (developers call this hanging). until the session with the open transaction, commits. This is a queue. so there may be several sessions ahead of you. but you will NOT error out.
Execute DDL. Your DDL will then run a lock with the NO WAIT. However, your session has aquired the lock. So you are good.
DDL auto-commits. This frees the locks.
DML statements will 'wait' or as developers call it 'hang' while the table is locked.
I use this in code that runs from a job to drop partitions. It works fine. It is in a database that is constantly inserting at a rate of several hundred inserts/second. No errors.
if you are wondering. Doing this in 11g. I have done this in 10g before as well in the past.
This error happens when the resource is busy. Check if you have any referential constraints in the query. Or even the tables that you have mentioned in the query may be busy. They might be engaged with some other job which will be definitely listed in the following query results:
SELECT * FROM V$SESSION WHERE STATUS = 'ACTIVE'
Find the SID,
SELECT * FROM V$OPEN_CURSOR WHERE SID = --the id
In my case, I was quite sure it was one of my own sessions which was blocking. Therefore, it was safe to do the following:
I found the offending session with:
SELECT * FROM V$SESSION WHERE OSUSER='my_local_username';
The session was inactive, but it still held the lock somehow. Note, that you may need to use some other WHERE condition in your case (e.g. try USERNAME or MACHINE fields).
Killed the session using the ID and SERIAL# acquired above:
alter system kill session '<id>, <serial#>';
Edited by #thermz: If none of the previous open-session queries work try this one. This query can help you to avoid syntax errors while killing sessions:
SELECT 'ALTER SYSTEM KILL SESSION '''||SID||','||SERIAL#||''' immediate;' FROM V$SESSION WHERE OSUSER='my_local_username_on_OS'
This happens when a session other than the one used to alter a table is holding a lock likely because of a DML (update/delete/insert). If you are developing a new system, it is likely that you or someone in your team issues the update statement and you could kill the session without much consequence. Or you could commit from that session once you know who has the session open.
If you have access to a SQL admin system use it to find the offending session. And perhaps kill it.
You could use v$session and v$lock and others but I suggest you google how to find that session and then how to kill it.
In a production system, it really depends. For oracle 10g and older, you could execute
LOCK TABLE mytable in exclusive mode;
alter table mytable modify mycolumn varchar2(5);
In a separate session but have the following ready in case it takes too long.
alter system kill session '....
It depends on what system do you have, older systems are more likely to not commit every single time. That is a problem since there may be long standing locks. So your lock would prevent any new locks and wait for a lock that who knows when will be released. That is why you have the other statement ready. Or you could look for PLSQL scripts out there that do similar things automatically.
In version 11g there is a new environment variable that sets a wait time. I think it likely does something similar to what I described. Mind you that locking issues don't go away.
ALTER SYSTEM SET ddl_lock_timeout=20;
alter table mytable modify mycolumn varchar2(5);
Finally it may be best to wait until there are few users in the system to do this kind of maintenance.
select
c.owner,
c.object_name,
c.object_type,
b.sid,
b.serial#,
b.status,
b.osuser,
b.machine
from
v$locked_object a,
v$session b,
dba_objects c
where
b.sid = a.session_id
and
a.object_id = c.object_id;
ALTER SYSTEM KILL SESSION 'sid,serial#';
As mentioned in other answers, this error is caused by concurrent DML operations running in other sessions. This causes Oracle to fail to lock the table for DDL with the default NOWAIT option.
For those without admin permissions in the database or who cannot kill/interrupt the other sessions, you can also precede your DDL operation with:
alter session set DDL_LOCK_TIMEOUT = 30;
--Run your DDL command, e.g.: alter table, etc.
I was receiving this error repeatedly in a database with background jobs doing large insert/update operations, and altering this parameter in the session allowed the DDL to continue after a few seconds of waiting for the lock.
For further information, see the comment from rshdev on this answer, this entry on oracle-base or the official docs on DDL_LOCK_TIMEOUT.
Just check for process holding the session and Kill it. Its back to normal.
Below SQL will find your process
SELECT s.inst_id,
s.sid,
s.serial#,
p.spid,
s.username,
s.program FROM gv$session s
JOIN gv$process p ON p.addr = s.paddr AND p.inst_id = s.inst_id;
Then kill it
ALTER SYSTEM KILL SESSION 'sid,serial#'
OR
some example I found online seems to need the instance id as well
alter system kill session '130,620,#1';
I had this error happen when I had 2 scripts I was running. I had:
A SQL*Plus session connected directly using a schema user account (account #1)
Another SQL*Plus session connected using a different schema user account (account #2), but connecting across a database link as the first account
I ran a table drop, then table creation as account #1.
I ran a table update on account #2's session. Did not commit changes.
Re-ran table drop/creation script as account #1. Got error on the drop table x command.
I solved it by running COMMIT; in the SQL*Plus session of account #2.
Your problem looks like you are mixing DML & DDL operations. See this URL which explains this issue:
http://www.orafaq.com/forum/t/54714/2/
I managed to hit this error when simply creating a table! There was obviously no contention problem on a table that didn't yet exist. The CREATE TABLE statement contained a CONSTRAINT fk_name FOREIGN KEY clause referencing a well-populated table. I had to:
Remove the FOREIGN KEY clause from the CREATE TABLE statement
Create an INDEX on the FK column
Create the FK
I solved this problem by closing one of my IDE tabs.
PL/SQL Developer
Version 10.0.5.1710
I also face the similar Issue. Nothing programmer has to do to resolve this error. I informed to my oracle DBA team. They kill the session and worked like a charm.
Solution given by Shashi's link is the best... no needs to contact dba or someone else
make a backup
create table xxxx_backup as select * from xxxx;
delete all rows
delete from xxxx;
commit;
insert your backup.
insert into xxxx (select * from xxxx_backup);
commit;

alter table constraint on unlock oracle

I am trying to write a script to be executed by a client who has no real knowledge of pl/sql,
I do a bunch of transactions in PL/sql to clean up their landscape and then have to add in some constraints to keep this from happening again, I commit automatically after the cleaning, and would like to finish my PL block with adding these constraints
only issue is I have no guarantee that the tables will not be locked when trying to add constraints to them, is there a wait until unlock type of command in oracle?
thank you, new to oracle and cannot seem to find this, I have combed through a bit of API but am at the point of time sensitivity and is proving very difficult to find when i think it seems like it would be a pretty regular issue with DB management
in your pl/sql block before execute any DDL you should call via execute immedaite :
LOCK TABLE <table_name> IN EXCLUSIVE MODE WAIT <n>;
where is number of seconds to wait.
But bear in mind even if you get lock after your first ddl it will be released because DDL commits automatically. So there is no way to guarantee that list of DDL commands will be executed one-by-one as in one transaction.
The command would be:
LOCK TABLE tab IN EXCLUSIVE MODE;
This will wait indefinitely if there is another session with a similar lock (which there should not be).
You can lock a table explicitly (with "WAIT") prior to a DDL, but that won't necessarily solve all of your problems if you are worried about another session holding an exclusive lock. Sounds more like you may have experienced an ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired due to a DML transaction in another session. This will eventually finish, so issuing the above lock command prior to ALTER TABLE will help you here. Just be aware that if there is a hung session elsewhere the LOCK TABLE command can wait indefinitely unless you have set a timeout.
So lets do an example:
In session A I start a transaction on tab
SQL> INSERT INTO tab VALUES(...);
In session B I attempt to add a constraint to the table.
SQL> alter table tab add constraint uk_name unique(name);
alter table tab add constraint uk_name unique(name)
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expire
So I'd have to try again. But instead if you precede your DDL with a LOCK ... EXCLUSIVE (WAIT)
SQL> lock table tab in exclusive mode;
-- indefinite period while the session A transaction blocks session B
Then session A commits or rolls back
SQL> commit;
Session B immediately continues when we see the lock command return Table(s) locked
Table(s) Locked.
SQL> alter table tab add constraint uk_name unique(name);
Table altered. (**comment Lock is released by the implicit commit issued the DDL statement)
SQL>
Since the DDL statement releases the lock, each DDL will need to be preceded with a fresh LOCK statement. If you want to use this, I recommend adding a timeout (as suggested in comments by Justin). Lets wait up to a minute before giving up.
SQL> lock table tab in exclusive mode WAIT 60;
Although if this is an unattended script on a busy database, I'd probably go with something more than 60 seconds. Just log everything to a spool file, and check the log later for errors.
Anything more than this sort of maintenance probably requires that you quiesce your database first, else just deal with the contention on a case by case basis.

ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired

Why am I getting this database error when I update a table?
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
Your table is already locked by some query. For example, you may have executed "select for update" and have not yet committed/rollbacked and fired another select query. Do a commit/rollback before executing your query.
from here ORA-00054: resource busy and acquire with NOWAIT specified
You can also look up the sql,username,machine,port information and get to the actual process which holds the connection
SELECT O.OBJECT_NAME, S.SID, S.SERIAL#, P.SPID, S.PROGRAM,S.USERNAME,
S.MACHINE,S.PORT , S.LOGON_TIME,SQ.SQL_FULLTEXT
FROM V$LOCKED_OBJECT L, DBA_OBJECTS O, V$SESSION S,
V$PROCESS P, V$SQL SQ
WHERE L.OBJECT_ID = O.OBJECT_ID
AND L.SESSION_ID = S.SID AND S.PADDR = P.ADDR
AND S.SQL_ADDRESS = SQ.ADDRESS;
Please Kill Oracle Session
Use below query to check active session info
SELECT
O.OBJECT_NAME,
S.SID,
S.SERIAL#,
P.SPID,
S.PROGRAM,
SQ.SQL_FULLTEXT,
S.LOGON_TIME
FROM
V$LOCKED_OBJECT L,
DBA_OBJECTS O,
V$SESSION S,
V$PROCESS P,
V$SQL SQ
WHERE
L.OBJECT_ID = O.OBJECT_ID
AND L.SESSION_ID = S.SID
AND S.PADDR = P.ADDR
AND S.SQL_ADDRESS = SQ.ADDRESS;
kill like
alter system kill session 'SID,SERIAL#';
(For example, alter system kill session '13,36543';)
Reference
http://abeytom.blogspot.com/2012/08/finding-and-fixing-ora-00054-resource.html
There is a very easy work around for this problem.
If you run a 10046 trace on your session (google this... too much to explain). You will see that before any DDL operation Oracle does the following:
LOCK TABLE 'TABLE_NAME' NO WAIT
So if another session has an open transaction you get an error. So the fix is... drum roll please. Issue your own lock before the DDL and leave out the 'NO WAIT'.
Special Note:
if you are doing splitting/dropping partitions oracle just locks the partition.
-- so yo can just lock the partition subpartition.
So...
The following steps fix the problem.
LOCK TABLE 'TABLE NAME'; -- you will 'wait' (developers call this hanging). until the session with the open transaction, commits. This is a queue. so there may be several sessions ahead of you. but you will NOT error out.
Execute DDL. Your DDL will then run a lock with the NO WAIT. However, your session has aquired the lock. So you are good.
DDL auto-commits. This frees the locks.
DML statements will 'wait' or as developers call it 'hang' while the table is locked.
I use this in code that runs from a job to drop partitions. It works fine. It is in a database that is constantly inserting at a rate of several hundred inserts/second. No errors.
if you are wondering. Doing this in 11g. I have done this in 10g before as well in the past.
This error happens when the resource is busy. Check if you have any referential constraints in the query. Or even the tables that you have mentioned in the query may be busy. They might be engaged with some other job which will be definitely listed in the following query results:
SELECT * FROM V$SESSION WHERE STATUS = 'ACTIVE'
Find the SID,
SELECT * FROM V$OPEN_CURSOR WHERE SID = --the id
In my case, I was quite sure it was one of my own sessions which was blocking. Therefore, it was safe to do the following:
I found the offending session with:
SELECT * FROM V$SESSION WHERE OSUSER='my_local_username';
The session was inactive, but it still held the lock somehow. Note, that you may need to use some other WHERE condition in your case (e.g. try USERNAME or MACHINE fields).
Killed the session using the ID and SERIAL# acquired above:
alter system kill session '<id>, <serial#>';
Edited by #thermz: If none of the previous open-session queries work try this one. This query can help you to avoid syntax errors while killing sessions:
SELECT 'ALTER SYSTEM KILL SESSION '''||SID||','||SERIAL#||''' immediate;' FROM V$SESSION WHERE OSUSER='my_local_username_on_OS'
This happens when a session other than the one used to alter a table is holding a lock likely because of a DML (update/delete/insert). If you are developing a new system, it is likely that you or someone in your team issues the update statement and you could kill the session without much consequence. Or you could commit from that session once you know who has the session open.
If you have access to a SQL admin system use it to find the offending session. And perhaps kill it.
You could use v$session and v$lock and others but I suggest you google how to find that session and then how to kill it.
In a production system, it really depends. For oracle 10g and older, you could execute
LOCK TABLE mytable in exclusive mode;
alter table mytable modify mycolumn varchar2(5);
In a separate session but have the following ready in case it takes too long.
alter system kill session '....
It depends on what system do you have, older systems are more likely to not commit every single time. That is a problem since there may be long standing locks. So your lock would prevent any new locks and wait for a lock that who knows when will be released. That is why you have the other statement ready. Or you could look for PLSQL scripts out there that do similar things automatically.
In version 11g there is a new environment variable that sets a wait time. I think it likely does something similar to what I described. Mind you that locking issues don't go away.
ALTER SYSTEM SET ddl_lock_timeout=20;
alter table mytable modify mycolumn varchar2(5);
Finally it may be best to wait until there are few users in the system to do this kind of maintenance.
select
c.owner,
c.object_name,
c.object_type,
b.sid,
b.serial#,
b.status,
b.osuser,
b.machine
from
v$locked_object a,
v$session b,
dba_objects c
where
b.sid = a.session_id
and
a.object_id = c.object_id;
ALTER SYSTEM KILL SESSION 'sid,serial#';
As mentioned in other answers, this error is caused by concurrent DML operations running in other sessions. This causes Oracle to fail to lock the table for DDL with the default NOWAIT option.
For those without admin permissions in the database or who cannot kill/interrupt the other sessions, you can also precede your DDL operation with:
alter session set DDL_LOCK_TIMEOUT = 30;
--Run your DDL command, e.g.: alter table, etc.
I was receiving this error repeatedly in a database with background jobs doing large insert/update operations, and altering this parameter in the session allowed the DDL to continue after a few seconds of waiting for the lock.
For further information, see the comment from rshdev on this answer, this entry on oracle-base or the official docs on DDL_LOCK_TIMEOUT.
Just check for process holding the session and Kill it. Its back to normal.
Below SQL will find your process
SELECT s.inst_id,
s.sid,
s.serial#,
p.spid,
s.username,
s.program FROM gv$session s
JOIN gv$process p ON p.addr = s.paddr AND p.inst_id = s.inst_id;
Then kill it
ALTER SYSTEM KILL SESSION 'sid,serial#'
OR
some example I found online seems to need the instance id as well
alter system kill session '130,620,#1';
I had this error happen when I had 2 scripts I was running. I had:
A SQL*Plus session connected directly using a schema user account (account #1)
Another SQL*Plus session connected using a different schema user account (account #2), but connecting across a database link as the first account
I ran a table drop, then table creation as account #1.
I ran a table update on account #2's session. Did not commit changes.
Re-ran table drop/creation script as account #1. Got error on the drop table x command.
I solved it by running COMMIT; in the SQL*Plus session of account #2.
Your problem looks like you are mixing DML & DDL operations. See this URL which explains this issue:
http://www.orafaq.com/forum/t/54714/2/
I managed to hit this error when simply creating a table! There was obviously no contention problem on a table that didn't yet exist. The CREATE TABLE statement contained a CONSTRAINT fk_name FOREIGN KEY clause referencing a well-populated table. I had to:
Remove the FOREIGN KEY clause from the CREATE TABLE statement
Create an INDEX on the FK column
Create the FK
I solved this problem by closing one of my IDE tabs.
PL/SQL Developer
Version 10.0.5.1710
I also face the similar Issue. Nothing programmer has to do to resolve this error. I informed to my oracle DBA team. They kill the session and worked like a charm.
Solution given by Shashi's link is the best... no needs to contact dba or someone else
make a backup
create table xxxx_backup as select * from xxxx;
delete all rows
delete from xxxx;
commit;
insert your backup.
insert into xxxx (select * from xxxx_backup);
commit;

How can I clean up dead connections using Oracle?

Right now I have a few new applications being developed against an Oracle Database, and sometimes they crash or fail to end correctly, etc... anyways the problem is they sometimes seem to leave their connections open, and I need to cleanup after them.
My question is if there is a way from the database-side of things to determine dead connections and clean them up?
Here's a page referring to connection timeout parameters you can set in Oracle 11g. I think the 'Abandon Connection Timeout' is what you're looking for.
You may also be interested in killing them. Running this script in SQL*Plus will give you a list of "kill" statements. You can pick out the ones you want to kill based on the sid and run those. Oracle has some of it's own internal connections, do not kill them.
SELECT 'alter system kill session ''' || sid || ',' || serial# || '''; ' || sql_id death
FROM v$session
/
I believe you are looking for the SQLNet.ora parameter EXPIRE_TIME which tells the database to send a probe to the client every few minutes to verify that the connection is still alive.
Here's how to identify the session to kill (you will need SID and SERIAL# to kill it). Should I mention that you need to make sure you're killing the right session? sys_context('userenv','sid') gets the SID of your own session.
SELECT s.inst_id,
s.sid,
s.serial#,
p.spid,
s.username,
s.osuser,
s.program
FROM gv$session s
JOIN gv$process p ON p.addr = s.paddr AND p.inst_id = s.inst_id
WHERE s.type != 'BACKGROUND';
You can then issue alter system kill session '[sid],[serial#]' as suggested by WW.
However the alter system kill session command does not forcibly kill the session, rather it asks the session to die. If the session is really hung, you will find that the request hangs for 60 seconds and then returns ORA-00031 Session marked for kill. And the session is still there.
In that case, first check that the session isn't rolling back a large transaction (cross reference the SID and SERIAL# from the above):
SELECT s.username,
s.osuser,
s.sid,
s.serial#,
t.used_ublk,
t.used_urec,
rs.segment_name,
r.rssize,
r.status
FROM v$transaction t,
v$session s,
v$rollstat r,
dba_rollback_segs rs
WHERE s.saddr = t.ses_addr
AND t.xidusn = r.usn
AND rs.segment_id = t.xidusn
ORDER BY t.used_ublk DESC;
If a transaction is rolling back you will see USED_UREC decreasing. Leave it to complete rollback.
Otherwise, ALTER SYSTEM DISCONNECT SESSION '[sid],[serial#]' IMMEDIATE; will forcibly disconnect the session and roll back the open transaction.
All the above info came from here.

Resources