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

Posted

技术标签:

【中文标题】ORA-00054: 资源繁忙并使用指定的 NOWAIT 获取或超时已过期【英文标题】:ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired 【发布时间】:2011-06-18 02:01:49 【问题描述】:

为什么我在更新表时收到此数据库错误?

第 1 行的错误:

【问题讨论】:

如果您发布导致错误的语句通常会有所帮助 【参考方案1】:

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

【讨论】:

我会在其中添加“在另一个会话中”。一个常见的情况是,您已经在工具中测试了更新,比如 SQL Developer 或 Toad,然后尝试在第一个会话仍然持有锁定的情况下在其他地方运行它。因此,您需要先提交/回滚另一个会话,然后才能再次运行更新。 很可能是 DML(插入/删除/更新)而不是查询。在另一个会话中。仅仅因为提问的人似乎是新手,答案可能是正确的。但是您不能代表生产系统中的其他用户提交。 嗯,让我遇到这个问题的原因是在 Toad:当我想删除一行时,一位同事和我在同一个表中,所以我无法删除它。当他切换到另一个表时,我能够删除行。它可能会帮助那里的人。但这仅适用于您在表中使用 Toad,而不是用于查询。 最近发生在我们的登台服务器(WebSphere 上的 Spring 应用程序)上。解决方案是通过将导致错误的语句移动到使用单独事务的单独更新服务中来将“整体”数据库更新脚本分成更小的部分:@Transactional(propagation = Propagation.REQUIRES_NEW)【参考方案2】:

从这里ORA-00054: resource busy and acquire with NOWAIT specified

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

【讨论】:

我不得不从查询中删除 s.port 但它让我找到了罪魁祸首 锁是暂时的。所以如果插入来了,那么你立即提交。它不会出现在这个查询中。如果您发出“DDL”,您仍然会收到错误消息。交易开放时。请参阅下面的帖子。这很容易解决。 我遇到了和 OP 一样的问题,但是我看不到您提到的任何表(例如,从 V$LOCKED_OBJECT 中选择 * 返回 ORA-00942: table or view不存在)。有什么想法吗? 您可能没有足够的权限查看管理视图。 跟进S.Port 问题:11.2 文档提到Port 作为V$Session 中的一个字段,但对我来说,使用11.1,S.Port 是无效的。可能是为 11.2 添加的吗?【参考方案3】:

请终止 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

【讨论】:

应该警告这个答案需要什么权限。我有CONNECTRESOURCE,但不是任何需要的,我拥有的帐户,并说ORA-00942: table or view does not exist。并非所有阅读此主题的人都会拥有SYS 帐户。 如果您还添加了选择列“S.OSUSER”,您将知道哪个用户正在运行该事务,并且如果您想在终止会话之前与用户核对,这将非常方便。 如果会话挂起,那么alter system kill session '13,36543' 将超时并且会话不会终止。在这种情况下,请参阅:***.com/a/24306610/587365 python 中使用connection object 向表中插入数据时出现了一些错误。然后 python script 在没有正确关闭 connection object 的情况下关闭。现在,当我尝试在另一个会话中删除表时,我收到“LOCKWAIT”错误。当我尝试kill session 时,我没有足够的特权。还有什么办法可以摆脱这种情况? 谢谢,这对我有帮助。【参考方案4】:

这个问题有一个非常简单的解决方法。

如果您在会话上运行 10046 跟踪(谷歌这个...太多解释)。您会看到,在任何 DDL 操作之前,Oracle 会执行以下操作:

LOCK TABLE 'TABLE_NAME' 无需等待

所以如果另一个会话有一个打开的事务,你会得到一个错误。所以解决办法是……请打鼓。在 DDL 之前发出您自己的锁并省略“NO WAIT”。

特别说明:

如果您正在拆分/删除分区,oracle 只会锁定分区。 -- 这样你就可以锁定分区子分区。

所以... 以下步骤可解决此问题。

    锁定表“表名”; -- 你会“等待”(开发者称之为挂起)。直到具有打开事务的会话提交。这是一个队列。所以可能有几个会议在你面前。但你不会出错。 执行 DDL。然后,您的 DDL 将使用 NO WAIT 运行锁定。但是,您的会话已获得锁定。所以你很好。 DDL 自动提交。这会释放锁。

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

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

如果你想知道。在 11g 中执行此操作。我以前也在 10g 中做过这个。

【讨论】:

好的,这是错误的。在 11g 中,使用 set_ddl_timeout,这仅在 11g 中可用。 oracle 在执行 DDL 之前会执行一次提交,因此它会释放锁。在 11g 中,您可以让 DDL 等待。我现在正在这样做。工作正常。 在 11g 中你应该使用 LOCK TABLE table_name IN EXCLUSIVE MODE; 如果您从批处理作业中获取 ORA-00054,这真的很有用,但我怀疑大多数登陆这里的人(包括 OP 和我)都在进行一些开发并且已经打开会话在他们试图删除和重新创建的同一张表上进行插入。 KILL SESSION 是这些人的正确答案。 @Bob 11g 和旧方式的示例代码会很好。 set_ddl_timeout 的语法是什么?应该是什么? @vapcguy 这在 11g 上对我有用:ALTER SYSTEM SET ddl_lock_timeout=20; 见 docs【参考方案5】:

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

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

找到 SID,

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

【讨论】:

不是每个人都可以访问这些视图。我得到ORA-00942: table or view does not exist 在这种情况下,数据库管理员负责提供这些信息。 并非总是如此。我不得不尝试让代码解决这个问题并解决它,我和我的服务帐户都没有这些权利。【参考方案6】:

在我的情况下,我很确定这是阻塞的我自己的会话之一。因此,执行以下操作是安全的:

我发现了有问题的会话:

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

会话不活动,但它仍然以某种方式保持锁定。请注意,您可能需要在您的情况下使用其他一些 WHERE 条件(例如,尝试 USERNAMEMACHINE 字段)。

使用上面获得的IDSERIAL# 终止会话:

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'

【讨论】:

如果之前的开放会话查询都不起作用,请尝试这个。【参考方案7】:

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

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

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

在生产系统中,这真的取决于。对于 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 '.... 终止的会话? 我不知道。【参考方案8】:

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

【讨论】:

【参考方案9】:

只需检查持有会话的进程并终止它。恢复正常了。

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

【讨论】:

【参考方案10】:

正如其他答案中提到的,此错误是由在其他会话中运行的并发 DML 操作引起的。这会导致 Oracle 无法使用默认的 NOWAIT 选项为 DDL 锁定表。

对于那些在数据库中没有管理员权限或无法终止/中断其他会话的人,您还可以在 DDL 操作之前使用:

alter session set DDL_LOCK_TIMEOUT = 30;
--Run your DDL command, e.g.: alter table, etc.

我在数据库中反复收到此错误,后台作业执行大型插入/更新操作,并且在会话中更改此参数允许 DDL 在等待锁定几秒钟后继续。

有关更多信息,请参阅 rshdev 对 this answer、this entry on oracle-base 或 official docs on DDL_LOCK_TIMEOUT 的评论。

【讨论】:

谢谢,遇到了同样的问题,用了你的提示【参考方案11】:

您的问题看起来像是在混合 DML 和 DDL 操作。请参阅解释此问题的此 URL:

http://www.orafaq.com/forum/t/54714/2/

【讨论】:

【参考方案12】:

我在运行 2 个脚本时发生了这个错误。我有:

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

我运行了一个表删除,然后以帐户 #1 的身份创建表。 我对帐户#2 的会话进行了表格更新。未提交更改。 将表删除/创建脚本重新运行为帐户 #1。 drop table x 命令出错。

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

【讨论】:

如果您没有删除表的权限,您会怎么做?不好的答案 Shakeer,这只是我在发生这种情况时正在做的一个例子——不是问题的解决方案——那是我最后一行——运行COMMIT;。如果您甚至不能删除一个表,那么您就没有权限更改任何会导致您陷入此问题的内容。【参考方案13】:

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

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

【讨论】:

我也遇到了同样的问题。从 ddl 语句中删除 fk 定义后,我能够创建表,但即使在列上创建索引后,我也无法添加它。 我能够解决它。首先,我在alter table add constraint 中添加了novalidate 子句。这以某种方式让它运行,但它锁定。然后我查看了会话锁以找出它锁定了哪个会话。然后我终止了那个会话。【参考方案14】:

我也面临类似的问题。程序员不需要做任何事情来解决这个错误。我通知了我的 Oracle DBA 团队。他们扼杀了会议并像魅力一样工作。

【讨论】:

还是有人要做点什么。如果 DBA 团队不知道该做什么以及如何终止会话怎么办?错误的答案。 如果 DBA 不知道如何终止会话,那么他就不适合工作 每个人都需要不时复习一下语法,以免弄错。【参考方案15】:

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

做好备份

create table xxxx_backup as select * from xxxx;

删除所有行

delete from xxxx;
commit;

插入您的备份。

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

【讨论】:

删除/截断不可互换。执行大量删除对性能有很大影响。这真的很糟糕。 我认为这是一种常见的模式。

以上是关于ORA-00054: 资源繁忙并使用指定的 NOWAIT 获取或超时已过期的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 提示:ORA-00054: 资源正忙,要求指定 NOWAIT

解决ORA-00054资源正忙的问题

Oracle中修改表名遇到“ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源, 或者超时失效”

使用plsql修改数据,报ORA-00054:资源正忙,但指定以NOWAIT方式获取资源,或者超时失效

ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源, 或者超时失效

ora-00054资源正忙,但指定以nowait方式