ORA-00054:资源正忙并且正在使用指定的NOWAIT进行获取,或者超时已过期


192

为什么更新表时出现此数据库错误?

第1行发生错误:ORA-00054:资源繁忙,并且指定了NOWAIT进行获取或超时已过期


22
如果您发布导致错误的语句,通常会有所帮助
Gary Myers

Answers:


221

您的表已被某些查询锁定。例如,您可能已执行“选择更新”,但尚未提交/回滚并触发了另一个选择查询。在执行查询之前执行提交/回滚。


46
我要在“另一个会话”中添加。一种常见的情况是,您已经在SQL Developer或Toad这样的工具中测试了更新,然后尝试在第一个会话仍保持锁定的同时在其他地方运行该更新。因此,您需要提交/回退另一个会话,然后才能再次运行更新。
Alex Poole

1
最可能是DML(插入/删除/更新),而不是查询。并在另一个会话中。只是因为提出要求的人似乎是新手,所以答案可能是正确的。但是您不能代表生产系统中的其他用户提交。
Arturo Hernandez 2013年

4
嗯,是什么让我遇到了这个问题是在Toad中:一位同事和我想删除一行的时候在同一张桌子上,所以我无法删除它。当他切换到另一个表时,我能够删除行。也许可以帮助某个人。但这仅适用于在表中使用Toad而不是用于查询的情况。
DatRid

最近发生在我们的登台服务器(WebSphere上的Spring应用程序)上。解决方案是通过将引起错误的语句移动到使用单独事务的单独更新服务中,将“整体”数据库更新脚本分成较小的部分:@Transactional(propagation = Propagation.REQUIRES_NEW)
Actc

100

从这里 ORA-00054:资源繁忙,并且使用NOWAIT指定获取

您还可以查找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;

5
我不得不从查询中删除s.port,但是它让我找到了罪魁祸首
Sibster 2013年

锁是瞬时的。因此,如果插入了,那么您立即提交。它不会显示在此查询中。如果发出“ DDL”,您仍然会收到错误消息。交易打开时。请参阅下面的文章。这很容易解决。
鲍勃,

4
我遇到了与OP相同的问题,但看不到您提到的任何表(例如,从V $ LOCKED_OBJECT中选择*,例如,返回ORA-00942:表或视图不存在)。有任何想法吗?
random_forest_fanatic

3
您可能没有足够的权限来查看管理视图。
njplumridge

问题的后续处理S.Port:11.2文档在中提到Port为字段V$Session,但对我而言,使用11.1 S.Port无效。可能是为11.2添加的吗?

63

请杀死Oracle会话

使用下面的查询来检查活动会话信息

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;

杀死像

alter system kill session 'SID,SERIAL#';

(例如,alter system kill session '13,36543';)

参考 http://abeytom.blogspot.com/2012/08/finding-and-fixing-ora-00054-resource.html


5
应该用所需的特权说明这个答案。我有CONNECTRESOURCE,但不是什么这个需求,我有,并说该帐户ORA-00942: table or view does not exist。并非每个阅读此主题的人都会拥有该SYS帐户。
vapcguy

如果还添加选择列“ S.OSUSER”,您将知道哪个用户正在运行该事务,并且在您要终止该会话之前与该用户核对时将非常方便。
Narasimha

如果会话被挂起,alter system kill session '13,36543'则将超时并且会话不会终止。在这种情况下,请参阅:stackoverflow.com/a/24306610/587365
Andrew Spencer,

在使用connection object中将数据插入表时,出现python了一些错误。然后python script关闭而不正确关闭connection object。现在,当我尝试在另一个会话中删除表时,出现“ LOCKWAIT”错误。当我尝试时,kill session我没有足够的特权。还有什么可以摆脱的呢?
sjd

17

有一个非常容易的解决此问题的方法。

如果您在会话上运行10046跟踪(对此进行了Google搜索...太多无法解释)。您将看到,在执行任何DDL操作之前,Oracle会执行以下操作:

锁定表“ TABLE_NAME”无需等待

因此,如果另一个会话具有未完成的事务,则会出现错误。所以解决方法是...请打鼓。在DDL之前发出自己的锁,并忽略“ NO WAIT”。

特别说明:

如果您要分割/删除分区,oracle只会锁定分区。-这样您就可以锁定分区子分区了。

所以...以下步骤解决了该问题。

  1. 锁定表“表名”;-您将“等待”(开发人员称此为挂起)。直到与未完成交易的会话提交。这是一个队列。因此,您可能要提前几个会议。但您不会出错。
  2. 执行DDL。然后,您的DDL将使用NO WAIT进行锁定。但是,您的会话已获取锁定。所以你很好。
  3. DDL自动提交。这将释放锁。

当表被锁定时,DML语句将“等待”或被开发人员称为“挂起”。

我在从作业运行以删除分区的代码中使用此代码。它工作正常。它在一个数据库中,它以每秒几百次插入的速度不断插入。没有错误。

如果您想知道。用11g做。我以前也曾在10g中做到这一点。


3
好,这是错误的。在11g中,请使用set_ddl_timeout,仅在11g中可用。oracle在执行DDL之前先进行提交,因此它释放了锁。在11g中,您可以等待DDL。我现在正在做。工作良好。
鲍勃,

3
在11g中,您应该在EXCLUSIVE MODE中使用LOCK TABLE table_name;
卡米尔·罗曼

1
如果您要从批处理作业中获取ORA-00054,这确实很有用,但是我怀疑大多数登陆此处的人(包括OP和我)正在做一些开发工作,并且让会话处于打开状态,并且他们在同一张桌子上插入重新尝试删除并重新创建。KILL SESSION是这些人的正确答案。
安德鲁·斯宾塞

@Bob 11g和旧方法的示例代码都不错。语法是set_ddl_timeout什么,应该是什么?
vapcguy

1
@vapcguy这对我来说适用于11g:ALTER SYSTEM SET ddl_lock_timeout=20;请参阅文档
rshdev

13

资源繁忙时会发生此错误。检查查询中是否有任何引用约束。甚至您在查询中提到的表可能都很忙。他们可能会从事其他工作,这些工作肯定会在以下查询结果中列出:

SELECT * FROM V$SESSION WHERE STATUS = 'ACTIVE'

找到SID,

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

1
并非所有人都可以访问这些视图。我懂了ORA-00942: table or view does not exist
vapcguy

在这种情况下,数据库管理员负责提供这些信息。
Arunchunaivendan

不总是。我不得不尝试让代码弄清楚并解决它,并且我和我的服务帐户都不会拥有这些权利。
vapcguy

7

当除用于更改表的会话以外的其他会话可能由于DML(更新/删除/插入)而持有锁时,会发生这种情况。如果您正在开发新系统,则您或团队中的某人可能会发布更新声明,并且您可能会在没有太大后果的情况下终止会话。或者,一旦知道谁打开了会话,就可以从该会话中提交。

如果您有权访问SQL管理系统,请使用它来查找有问题的会话。也许杀死它。

您可以使用v $ session和v $ lock等,但是我建议您使用google如何找到该会话,然后如何杀死它。

在生产系统中,这确实取决于。对于oracle 10g及更早版本,您可以执行

LOCK TABLE mytable in exclusive mode;
alter table mytable modify mycolumn varchar2(5);

在单独的会话中,但准备以下内容以防万一太长。

alter system kill session '....

这取决于您拥有的系统,较旧的系统很可能不会每次都提交。这是一个问题,因为可能有很长的锁。因此,您的锁将阻止任何新的锁,并等待知道何时释放的锁。这就是为什么您要准备另一条语句的原因。或者,您也可以在其中寻找可以自动执行类似操作的PLSQL脚本。

在版本11g中,有一个新的环境变量可以设置等待时间。我认为这可能与我所描述的类似。提醒您,锁定问题不会消失。

ALTER SYSTEM SET ddl_lock_timeout=20;
alter table mytable modify mycolumn varchar2(5);

最后,最好等到系统中的用户很少进行此类维护。


alter system kill session '....如果您无权访问管理视图,如何找到要杀死的会话?
vapcguy

我不知道
Arturo Hernandez

7

就我而言,我非常确定这是我自己的会话中的一个被阻塞。因此,执行以下操作是安全的:

  • 我发现有以下问题:

    SELECT * FROM V$SESSION WHERE OSUSER='my_local_username';

    该会话处于非活动状态,但仍以某种方式锁定了该锁。请注意,您可能需要根据情况使用其他WHERE条件(例如try USERNAMEMACHINEfield)。

  • 使用ID和杀死SERIAL#了上面的会话:

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

@thermz编辑:如果以前的打开会话查询均不起作用,请尝试执行此操作。此查询可以帮助您避免在终止会话时避免语法错误:

  • SELECT 'ALTER SYSTEM KILL SESSION '''||SID||','||SERIAL#||''' immediate;' FROM V$SESSION WHERE OSUSER='my_local_username_on_OS'

如果以前的开放会话查询均不起作用,请尝试执行此操作。
thermz

5

只需检查举行会议的进程并杀死它即可。它恢复正常。

下面的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;

然后杀死它

ALTER SYSTEM KILL SESSION 'sid,serial#'

要么

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



4

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


3

仅创建表时,我设法解决了该错误!显然,在尚不存在的表上没有争用问题。该CREATE TABLE语句包含一个CONSTRAINT fk_name FOREIGN KEY引用填充良好的表的子句。我不得不:

  • 从CREATE TABLE语句中删除FOREIGN KEY子句
  • 在FK列上创建一个INDEX
  • 创建FK

我只是有同样的问题。从ddl语句中删除fk定义后,我可以创建表,但是即使在列上创建索引后也无法添加表。
vadipp

我能够解决它。首先,我在中添加了一个novalidate子句alter table add constraint。这样可以使其运行,但会锁定。然后,我查看了会话锁,以找出它锁定在哪个会话上。然后我杀死了那个会议。
vadipp

3

当我运行2个脚本时,发生了此错误。我有:

  • 使用模式用户帐户(帐户1)直接连接的SQL * Plus会话
  • 另一个SQL * Plus会话使用不同的架构用户帐户(帐户2)连接,但通过数据库链接作为第一个帐户进行连接

我放了一张桌子,然后以帐户#1的身份创建了表格。我在帐户#2的会话上进行了表更新。没有提交更改。以帐户#1重新运行表删除/创建脚本。在drop table x命令上出错。

我通过COMMIT;在帐户#2的SQL * Plus会话中运行来解决此问题。


如果您没有删除表的权限,那该怎么办?错误的答案
Shakeer Hussain

1
Shakeer,这只是我遇到的事情的一个示例,而不是问题的解决方案,而这是我最后一行运行a的情况COMMIT;。如果您甚至无法删除表,那么您将无权更改首先会使您陷入此问题的任何内容。
vapcguy

-2

我也面临类似的问题。程序员无需执行任何操作即可解决此错误。我通知了我的Oracle DBA团队。他们扼杀了会议并像魅力一样工作。


1
仍然有人必须做些事情。如果DBA团队不知道该怎么办以及如何终止会话该怎么办?错误的答案。
vapcguy

1
如果DBA不知道如何结束会话,然后他不适合工作
Shakeer侯赛因

每个人都需要不时地重新学习语法,以免出错。
vapcguy

-5

Shashi链接给出的解决方案是最好的...无需联系dba或其他人

进行备份

create table xxxx_backup as select * from xxxx;

删除所有行

delete from xxxx;
commit;

插入您的备份。

insert into xxxx (select * from xxxx_backup);
commit;

10
删除/截断不可互换。执行大量删除操作会对性能产生重大影响。这真的很糟糕。
鲍勃,

我认为这是一种常见的模式。
肖恩·薛
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.