ChatGPT解决这个技术问题 Extra ChatGPT

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

It generally helps if you post the statement that leads to the error

P
Paweł Obrok

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.


I'd add 'in another session' to that. One common scenario is that you've tested the update in a tool, say SQL Developer or Toad, and have then tried to run it somewhere else while the first session still holds the lock. So you need to commit/rollback the other session before you can run the update again.
Most likely DML (insert/delete/update) rather than a query. And in another session. Just because the guy who asked seems to be a newbie the answer may be correct. But you CANNOT commit in behalf of other users in a production system.
Well, what made me having that problem was in Toad: A colleague was in the same table as i were when i wanted to delete a row, and so i couldnt delete it. When he switched to another table i was able to delete rows. It maybe help someone out there. But this is only if you work with Toad inside the tables, and not for querys.
recently occured on our staging server (Spring application on WebSphere). Solution was to separate the "monolithic" database update script into smaller pieces by moving the error-causing statements into a separate update service which uses a separate transaction: @Transactional(propagation = Propagation.REQUIRES_NEW)
C
Community

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;

I had to remove s.port from the query but It let me find the culprit
locks are transient. so if the insert comes, then you commit immediately. it won't show up in this query. you can still get the error if you issue the 'DDL'. while the transaction is open. see my post below .This is really easy to work around.
I'm having the same problem as the OP, but I can't see any of the tables you mention (select * from V$LOCKED_OBJECT, for example, returns ORA-00942: table or view does not exist). Any ideas?
You might not have sufficient privileges to look at the management views.
Follow-up to the S.Port problem: the 11.2 docs mention Port as a field in V$Session, but for me, using 11.1, S.Port is invalid. Was it added for 11.2, maybe?
u
user5670895

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


Should caveat this answer with what privileges are required. I have CONNECT and RESOURCE, but not whatever this needs, with the account I have, and says ORA-00942: table or view does not exist. Not everyone reading this thread will have the SYS account.
If you add the select column 'S.OSUSER' as well you will know which user was running that transaction and it will be handy in case you want to check with the user before killing the session.
If the session is hung, then alter system kill session '13,36543' will timeout and the session won't die. In that case see: stackoverflow.com/a/24306610/587365
While inserting data to a table using a connection object in python i got some error. Then the python script is closed without properly closing the connection object. Now i am getting the "LOCKWAIT" error when i try to drop the table in another session. When i try kill session i dont have enough privilage. What else can be done to get rid of this?
Thanks Man, This helped me.
B
Bob

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.


ok, this is wrong. in 11g, use the set_ddl_timeout, This is only available in 11g. oracle does a commit before doing DDL, so it releases the lock. In 11g, you can have your DDL wait. I am doing that now. Works fine.
in 11g you should use LOCK TABLE table_name IN EXCLUSIVE MODE;
This is really useful if you're getting the ORA-00054 from batch jobs, but I suspect most people landing here (including the OP, and me) are doing some development and have left a session open doing inserts on the same table they're trying to drop and recreate. KILL SESSION is the right answer for these people.
@Bob Example code for both 11g and the old way would be nice. What is the syntax for set_ddl_timeout and what should it be?
@vapcguy this worked for me on 11g: ALTER SYSTEM SET ddl_lock_timeout=20; see docs
A
Arunchunaivendan

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

Not everyone will have access to these views. I get ORA-00942: table or view does not exist.
In such cases, DB Admins are responsible for providing those information.
Not always. I had to try to have code figure this out and work around it, and neither I nor my service account will have these rights.
w
wrygiel

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 ', ';

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'


If none of the previous open-session queries work try this one.
A
Arturo Hernandez

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.


And how do you find out the session to kill for alter system kill session '.... if you don't have access to the management views?
That I don't know.
h
harun ugur

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#';


d
divieira

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.


Thanks, was facing the same issue, used your tip
M
Mathavan John

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';


v
vapcguy

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.


If you don't have permissions to drop a table then what you will do? Bad answer
Shakeer, that was just an example of what I was doing when it happened to me - not the solution to the problem - that was in my very last line - running a COMMIT;. If you can't even drop a table, you don't have the permissions to alter anything that would get you into this issue in the first place.
S
Shashi

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/


b
bwperrin

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 just had the same problem. I was able to create the table after I removed the fk definition from the ddl statement, but I'm unable to add it even after I created the index on the column.
I was able to solve it. First, I added a novalidate clause to the alter table add constraint. This somehow lets it run, but it locks. Then I looked at the session locks to find out on which session it locks. And then I killed that session.
S
Shakeer Hussain

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.


Somebody still has to do something. What if the DBA team doesn't know what to do, and how to kill a session? Bad answer.
If DBA doesn't know how to kill session then he unfit to work
Everyone needs a refresher on syntax from time to time to avoid getting it wrong.
t
tafibo

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;

delete/truncate are not interchangeable. performing large numbers of deletes have massive performance implications. This is really bad.
I thought this is a common pattern.

关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now