ORA-00054: recurso ocupado e adquirido com NOWAIT especificado ou tempo limite expirado


193

Por que estou recebendo esse erro de banco de dados quando atualizo uma tabela?

ERRO na linha 1: ORA-00054: recurso ocupado e adquirido com NOWAIT especificado ou o tempo limite expirou


22
Geralmente ajuda se você postar a declaração que leva ao erro
Gary Myers

Respostas:


222

Sua tabela já está bloqueada por alguma consulta. Por exemplo, você pode ter executado "selecionar para atualização" e ainda não confirmou / retrocedeu e disparou outra consulta de seleção. Faça uma confirmação / reversão antes de executar sua consulta.


47
Eu adicionaria 'em outra sessão' a ​​isso. Um cenário comum é que você testou a atualização em uma ferramenta, digamos SQL Developer ou Toad, e tentou executá-la em outro lugar enquanto a primeira sessão ainda mantinha o bloqueio. Portanto, você precisa confirmar / reverter a outra sessão antes de poder executar a atualização novamente.
Alex Poole

1
Provavelmente DML (inserir / excluir / atualizar) em vez de uma consulta. E em outra sessão. Só porque o cara que perguntou parece ser um novato, a resposta pode estar correta. Mas você NÃO PODE confirmar em nome de outros usuários em um sistema de produção.
Arturo Hernandez

4
Bem, o que me levou a ter esse problema foi no Toad: um colega estava na mesma tabela que eu estava quando queria excluir uma linha e, portanto, não consegui excluí-la. Quando ele mudou para outra tabela, eu pude excluir linhas. Talvez ajude alguém lá fora. Mas isso é apenas se você trabalha com o Toad dentro das tabelas, e não para consultas.
DatRid

ocorreu recentemente em nosso servidor intermediário (aplicativo Spring no WebSphere). A solução foi separar o script de atualização do banco de dados "monolítico" em partes menores, movendo as instruções causadoras de erros para um serviço de atualização separado que usa uma transação separada: @Transactional (propagation = Propagation.REQUIRES_NEW)
actc

102

daqui ORA-00054: recurso ocupado e adquirido com NOWAIT especificado

Você também pode procurar as informações sql, nome de usuário, máquina, porta e acessar o processo real que mantém a conexão

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
Eu tinha que remover s.port a partir da consulta, mas Ele deixe-me encontrar o culpado
Sibster

bloqueios são transitórios. portanto, se a inserção vier, você confirmará imediatamente. não aparecerá nesta consulta. você ainda pode receber o erro se emitir o 'DDL'. enquanto a transação está aberta. veja meu post abaixo. Isso é realmente fácil de contornar.
31413 Bob

4
Estou tendo o mesmo problema que o OP, mas não consigo ver nenhuma das tabelas mencionadas (selecione * em V $ LOCKED_OBJECT, por exemplo, retorna ORA-00942: a tabela ou a exibição não existe). Alguma ideia?
random_forest_fanatic

3
Você pode não ter privilégios suficientes para examinar as visualizações de gerenciamento.
Njplumridge 25/09

Acompanhamento do S.Portproblema: os documentos 11.2 são mencionados Portcomo um campo em V$Session, mas para mim, o uso do 11.1 S.Porté inválido. Foi adicionado para 11.2, talvez?

63

Matar Sessão Oracle

Use a consulta abaixo para verificar as informações da sessão ativa

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;

mate como

alter system kill session 'SID,SERIAL#';

(Por exemplo alter system kill session '13,36543',;)

Referência http://abeytom.blogspot.com/2012/08/finding-and-fixing-ora-00054-resource.html


5
Deve ressaltar esta resposta com quais privilégios são necessários. Eu tenho CONNECTe RESOURCE, mas não o que for necessário, com a conta que tenho e diz ORA-00942: table or view does not exist. Nem todo mundo lendo este tópico terá a SYSconta.
vapcguy

Se você adicionar a coluna de seleção 'S.OSUSER', também saberá qual usuário estava executando essa transação e será útil caso queira verificar com o usuário antes de encerrar a sessão.
precisa

Se a sessão for interrompida, alter system kill session '13,36543'o tempo limite será excedido e a sessão não terminará. Nesse caso, consulte: stackoverflow.com/a/24306610/587365
Andrew Spencer

Ao inserir dados em uma tabela usando um connection objectin, pythonrecebi algum erro. Então o python scripté fechado sem fechar corretamente o connection object. Agora, estou recebendo o erro "LOCKWAIT" quando tento soltar a tabela em outra sessão. Quando tento, kill sessionnão tenho privilégio suficiente. O que mais pode ser feito para se livrar disso?
Sjd 28/08/19

17

Existe uma solução muito fácil para esse problema.

Se você executar um rastreamento 10046 em sua sessão (pesquise no google isso ... demais para explicar). Você verá que, antes de qualquer operação DDL, a Oracle faz o seguinte:

LOCK TABLE 'TABLE_NAME' SEM ESPERA

Portanto, se outra sessão tiver uma transação aberta, você receberá um erro. Então a solução é ... rolar o tambor, por favor. Emita seu próprio bloqueio antes da DDL e deixe de fora o 'NO WAIT'.

Nota especial:

se você estiver dividindo / largando partições, o oracle apenas bloqueia a partição. - para que você possa bloquear a subpartição da partição.

Então ... As etapas a seguir corrigem o problema.

  1. TABELA DE BLOQUEIO 'NOME DA TABELA'; - você 'espera' (os desenvolvedores chamam isso de suspenso). até a sessão com a transação aberta, confirma. Esta é uma fila. então pode haver várias sessões antes de você. mas você NÃO errará.
  2. Execute DDL. Seu DDL executará um bloqueio com o NO WAIT. No entanto, sua sessão adquiriu o bloqueio. Então você é bom.
  3. Confirmações automáticas de DDL. Isso libera os bloqueios.

As instruções DML 'aguardam' ou como os desenvolvedores chamam de 'travar' enquanto a tabela está bloqueada.

Eu uso isso no código que é executado em um trabalho para descartar partições. Funciona bem. Ele está em um banco de dados que é constantemente inserido a uma taxa de várias centenas de inserções / segundo. Sem erros.

se você está se perguntando. Fazendo isso em 11g. Eu já fiz isso em 10g antes e no passado.


3
ok, isso está errado. no 11g, use o set_ddl_timeout, disponível apenas no 11g. O oracle faz uma consolidação antes de executar o DDL, portanto libera o bloqueio. No 11g, você pode esperar sua DDL. Eu estou fazendo isso agora. Funciona bem.
22413 Bob

3
no 11g você deve usar LOCK TABLE table_name NO MODO EXCLUSIVO;
Kamil Roman

1
Isso é realmente útil se você estiver obtendo o ORA-00054 de trabalhos em lotes, mas suspeito que a maioria das pessoas que chegam aqui (incluindo o OP e eu) estão desenvolvendo algum desenvolvimento e deixaram uma sessão aberta fazendo inserções na mesma tabela que eles ' está tentando soltar e recriar. KILL SESSIONé a resposta certa para essas pessoas.
Andrew Spencer

@Bob Exemplo de código para 11g e da maneira antiga seria bom. Qual é a sintaxe set_ddl_timeoute qual deve ser?
vapcguy

1
@vapcguy isso funcionou para mim no 11g: ALTER SYSTEM SET ddl_lock_timeout=20;ver docs
rshdev

13

Este erro ocorre quando o recurso está ocupado. Verifique se você tem alguma restrição referencial na consulta. Ou mesmo as tabelas que você mencionou na consulta podem estar ocupadas. Eles podem estar envolvidos com algum outro trabalho que será definitivamente listado nos seguintes resultados da consulta:

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

Encontre o SID,

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

1
Nem todo mundo terá acesso a esses pontos de vista. Eu entendo ORA-00942: table or view does not exist.
Vapcguy 23/05

Nesses casos, os administradores de banco de dados são responsáveis ​​por fornecer essas informações.
Arunchunaivendan

Nem sempre. Eu tive que tentar fazer com que o código resolvesse isso e resolvê-lo, e nem eu nem minha conta de serviço teremos esses direitos.
vapcguy

7

Isso acontece quando uma sessão diferente da usada para alterar uma tabela está mantendo um bloqueio devido a um DML (atualização / exclusão / inserção). Se você estiver desenvolvendo um novo sistema, é provável que você ou alguém da sua equipe emita a declaração de atualização e você poderá interromper a sessão sem muita consequência. Ou você pode confirmar a partir dessa sessão depois de saber quem está com a sessão aberta.

Se você tiver acesso a um sistema de administração SQL, use-o para encontrar a sessão incorreta. E talvez mate.

Você pode usar v $ session e v $ lock e outros, mas sugiro que você pesquise no google como encontrar essa sessão e depois como matá-la.

Em um sistema de produção, isso realmente depende. Para o Oracle 10g e mais antigo, você pode executar

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

Em uma sessão separada, mas tenha o seguinte pronto, caso demore muito.

alter system kill session '....

Depende de qual sistema você possui; é mais provável que os sistemas mais antigos não sejam confirmados todas as vezes. Esse é um problema, pois pode haver bloqueios de longa data. Portanto, seu bloqueio impediria novos bloqueios e esperaria um bloqueio que sabe quando será liberado. É por isso que você tem a outra declaração pronta. Ou você pode procurar por scripts PLSQL por aí que fazem coisas semelhantes automaticamente.

Na versão 11g, há uma nova variável de ambiente que define um tempo de espera. Eu acho que provavelmente faz algo semelhante ao que eu descrevi. Lembre-se de que os problemas de bloqueio não desaparecem.

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

Finalmente, pode ser melhor esperar até que haja poucos usuários no sistema para fazer esse tipo de manutenção.


E como você descobre a sessão para matar alter system kill session '....se não tem acesso às visualizações de gerenciamento?
Vapcguy

Isso eu não sei.
Arturo Hernandez

7

No meu caso, eu tinha certeza de que era uma das minhas próprias sessões que estava bloqueando. Portanto, era seguro fazer o seguinte:

  • Encontrei a sessão ofensiva com:

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

    A sessão estava inativa , mas ainda mantinha a trava de alguma forma. Observe que você pode precisar usar alguma outra condição WHERE no seu caso (por exemplo, tentativa USERNAMEou MACHINEcampos).

  • Matou a sessão usando o IDe SERIAL#adquirido acima:

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

Editado por @thermz: Se nenhuma das consultas de sessão aberta anteriores funcionar, tente esta. Esta consulta pode ajudar a evitar erros de sintaxe ao matar sessões:

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

Se nenhuma das consultas de sessão aberta anteriores funcionar, tente esta.
thermz

5

Basta verificar o processo de realização da sessão e matá-lo. Está de volta ao normal.

Abaixo do SQL, você encontrará seu processo

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;

Então mate

ALTER SYSTEM KILL SESSION 'sid,serial#'

OU

algum exemplo que encontrei on-line parece precisar do ID da instância, bem como alterar a sessão de interrupção do sistema '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

Consegui acertar esse erro ao simplesmente criar uma tabela! Obviamente, não havia nenhum problema de contenção em uma tabela que ainda não existia. A CREATE TABLEdeclaração continha uma CONSTRAINT fk_name FOREIGN KEYcláusula referenciando uma tabela bem preenchida. Eu precisei:

  • Remova a cláusula FOREIGN KEY da instrução CREATE TABLE
  • Crie um índice na coluna FK
  • Crie o FK

Eu apenas tive o mesmo problema. Consegui criar a tabela depois de remover a definição fk da instrução ddl, mas não consigo adicioná-la mesmo depois de criar o índice na coluna.
precisa saber é

Eu fui capaz de resolver isso. Primeiro, adicionei uma novalidatecláusula ao arquivo alter table add constraint. De alguma forma, isso funciona, mas bloqueia. Depois, observei os bloqueios da sessão para descobrir em qual sessão ele bloqueia. E então eu matei aquela sessão.
precisa saber é

3

Eu tive esse erro acontecer quando eu tinha 2 scripts que eu estava executando. Eu tinha:

  • Uma sessão SQL * Plus conectada diretamente usando uma conta de usuário de esquema (conta nº 1)
  • Outra sessão do SQL * Plus conectada usando uma conta de usuário de esquema diferente (conta nº 2), mas conectando-se através de um link de banco de dados como a primeira conta

Executei uma queda da tabela e depois a criação da tabela como a conta nº 1. Fiz uma atualização de tabela na sessão da conta nº 2. Não efetuou alterações. Executei novamente o script de remoção / criação da tabela como a conta nº 1. Erro nodrop table x comando.

Eu o resolvi executando COMMIT;na sessão SQL * Plus da conta # 2.


Se você não tem permissão para descartar uma tabela, o que você fará? Resposta ruim
Shakeer Hussain

1
Shakeer, esse foi apenas um exemplo do que eu estava fazendo quando aconteceu comigo - não a solução para o problema - que estava na minha última linha - executando a COMMIT;. Se você não consegue nem soltar uma tabela, não tem permissão para alterar nada que o levasse a esse problema em primeiro lugar.
vapcguy

-2

Eu também enfrento o problema semelhante. Nada que o programador precise fazer para resolver esse erro. Eu informei à minha equipe de DBA da Oracle. Eles matam a sessão e funcionaram como um encanto.


1
Alguém ainda tem que fazer alguma coisa. E se a equipe do DBA não souber o que fazer e como matar uma sessão? Resposta ruim.
vapcguy

1
Se DBA não sabe como matar sessão, então ele inaptos para o trabalho
Shakeer Hussain

Todo mundo precisa de uma atualização na sintaxe de tempos em tempos para evitar erros.
Vapcguy

-5

A solução fornecida pelo link de Shashi é a melhor ... não é necessário entrar em contato com a dba ou com outra pessoa

faça um backup

create table xxxx_backup as select * from xxxx;

excluir todas as linhas

delete from xxxx;
commit;

insira seu backup.

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

10
excluir / truncar não são intercambiáveis. executar um grande número de exclusões tem implicações enormes no desempenho. Isso é muito ruim.
31413 Bob

Eu pensei que este é um padrão comum.
Shawn Xue
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.