简体   繁体   English

ORA-00054: 资源繁忙并使用指定的 NOWAIT 获取或超时已过期

[英]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第 1 行出现错误:ORA-00054:资源繁忙并使用指定的 NOWAIT 获取或超时过期

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 从这里开始ORA-00054:资源繁忙,并且指定了NOWAIT来获取

You can also look up the sql,username,machine,port information and get to the actual process which holds the connection 您还可以查找sql​​,用户名,机器,端口信息,并找到包含连接的实际进程

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 请杀死Oracle会话

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' ;) (例如, alter system kill session '13,36543' ;)

Reference http://abeytom.blogspot.com/2012/08/finding-and-fixing-ora-00054-resource.html 参考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). 如果您在会话上运行了10046跟踪(对此进行了Google搜索...解释太多了)。 You will see that before any DDL operation Oracle does the following: 您将在执行任何DDL操作之前看到Oracle执行以下操作:

LOCK TABLE 'TABLE_NAME' NO WAIT 锁定表“ TABLE_NAME”无需等待

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'. 在DDL之前发出自己的锁,并忽略“ NO WAIT”。

Special Note: 特别说明:

if you are doing splitting/dropping partitions oracle just locks the partition. 如果您要分割/删除分区,oracle只会锁定分区。 -- so yo can just lock the partition subpartition. -这样您就可以锁定分区子分区了。

So... The following steps fix the problem. 所以...以下步骤解决了该问题。

  1. 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. 但您不会出错。
  2. Execute DDL. 执行DDL。 Your DDL will then run a lock with the NO WAIT. 然后,您的DDL将使用NO WAIT运行锁。 However, your session has aquired the lock. 但是,您的会话已获取锁定。 So you are good. 所以你很好。
  3. DDL auto-commits. DDL自动提交。 This frees the locks. 这将释放锁。

DML statements will 'wait' or as developers call it 'hang' while the table is locked. 当表被锁定时,DML语句将“等待”或被开发人员称为“挂起”。

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. 用11g做。 I have done this in 10g before as well in the past. 我以前也用10g做过。

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, 找到SID,

SELECT * FROM V$OPEN_CURSOR WHERE SID = --the id

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). 当除用于更改表的会话以外的其他会话可能由于DML(更新/删除/插入)而持有锁时,会发生这种情况。 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. 如果您有权访问SQL管理系统,请使用它来查找有问题的会话。 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. 您可以使用v $ session和v $ lock等,但是我建议您使用google如何找到该会话,然后如何杀死它。

In a production system, it really depends. 在生产系统中,这确实取决于。 For oracle 10g and older, you could execute 对于oracle 10g及更早版本,您可以执行

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. 或者,您可以寻找在那里自动执行类似操作的PLSQL脚本。

In version 11g there is a new environment variable that sets a wait time. 在版本11g中,有一个新的环境变量可以设置等待时间。 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. 最后,最好等到系统中的用户很少进行此类维护。

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 (eg try USERNAME or MACHINE fields). 请注意,在这种情况下,您可能需要使用其他一些WHERE条件(例如,尝试USERNAMEMACHINE字段)。

  • Killed the session using the ID and SERIAL# acquired above: 使用上面获得的IDSERIAL#终止了会话:

    alter system kill session '<id>, <serial#>';

Edited by @thermz: If none of the previous open-session queries work try this one. @thermz编辑:如果以前的打开会话查询均不起作用,请尝试执行此操作。 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'

As mentioned in other answers, this error is caused by concurrent DML operations running in other sessions.如其他答案中所述,此错误是由其他会话中运行的并发 DML 操作引起的。 This causes Oracle to fail to lock the table for DDL with the default NOWAIT option.这会导致 Oracle 无法使用默认的 NOWAIT 选项锁定 DDL 表。

For those without admin permissions in the database or who cannot kill/interrupt the other sessions, you can also precede your DDL operation with:对于那些在数据库中没有管理员权限或无法终止/中断其他会话的人,您还可以在 DDL 操作之前使用:

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.我在数据库中反复收到此错误,后台作业执行大型插入/更新操作,并且在 session 中更改此参数允许 DDL 在等待锁定几秒钟后继续。

For further information, see the comment from rshdev on this answer , this entry on oracle-base or the official docs on DDL_LOCK_TIMEOUT .有关详细信息,请参阅 rshdev对此答案的评论、 oracle-base 上的此条目DDL_LOCK_TIMEOUT 上的官方文档

Just check for process holding the session and Kill it. 只需检查举行会议的进程并杀死它即可。 Its back to normal. 它恢复正常。

Below SQL will find your process 下面的SQL将找到您的过程

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'; 我在网上发现的一些示例似乎还需要实例ID以及更改系统终止会话“ 130,620,@ 1”;

Your problem looks like you are mixing DML & DDL operations. 您的问题看起来像是在混合DML和DDL操作。 See this URL which explains this issue: 请参阅解释此问题的URL:

http://www.orafaq.com/forum/t/54714/2/ 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. CREATE TABLE语句包含一个CONSTRAINT fk_name FOREIGN KEY子句,该子句引用了填充良好的表。 I had to: 我不得不:

  • Remove the FOREIGN KEY clause from the CREATE TABLE statement 从CREATE TABLE语句中删除FOREIGN KEY子句
  • Create an INDEX on the FK column 在FK列上创建一个INDEX
  • Create the FK 创建FK

I had this error happen when I had 2 scripts I was running. 当我运行2个脚本时,发生了此错误。 I had: 我有:

  • A SQL*Plus session connected directly using a schema user account (account #1) 使用架构用户帐户(帐户#1)直接连接的SQL * Plus会话
  • Another SQL*Plus session connected using a different schema user account (account #2), but connecting across a database link as the first account 另一个SQL * Plus会话使用不同的架构用户帐户(帐户2)连接,但作为第一个帐户通过数据库链接进行连接

I ran a table drop, then table creation as account #1. 我运行了一个表放置,然后以帐户#1的身份创建了表。 I ran a table update on account #2's session. 我在帐户#2的会话上进行了表更新。 Did not commit changes. 没有提交更改。 Re-ran table drop/creation script as account #1. 以帐户#1重新运行表删除/创建脚本。 Got error on the drop table x command. drop table x命令上出错。

I solved it by running COMMIT; 我通过运行COMMIT;解决了这个问题COMMIT; in the SQL*Plus session of account #2. 在帐户#2的SQL * Plus会话中。

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

I solved this problem by closing one of my IDE tabs.我通过关闭我的 IDE 选项卡之一解决了这个问题。

PL/SQL Developer Version 10.0.5.1710 PL/SQL 开发者版本 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. 我通知了我的Oracle DBA团队。 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 Shashi链接给出的解决方案是最好的...无需联系dba或其他人

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM