ORA-00054: risorse occupate e acquisite con NOWAIT specificato o timeout scaduto


193

Perché visualizzo questo errore del database quando aggiorno una tabella?

ERRORE alla riga 1: ORA-00054: risorse occupate e acquisite con NOWAIT specificato o timeout scaduto


22
In genere aiuta se pubblichi l'affermazione che porta all'errore
Gary Myers,

Risposte:


223

La tua tabella è già bloccata da qualche query. Ad esempio, potresti aver eseguito "seleziona per aggiornamento" e non hai ancora eseguito il commit / rollback e attivato un'altra query di selezione. Effettuare un commit / rollback prima di eseguire la query.


47
Aggiungerei "in un'altra sessione" a quello. Uno scenario comune è che hai testato l'aggiornamento in uno strumento, ad esempio SQL Developer o Toad, e poi hai provato a eseguirlo da qualche altra parte mentre la prima sessione mantiene ancora il blocco. Quindi è necessario eseguire il commit / rollback dell'altra sessione prima di poter eseguire nuovamente l'aggiornamento.
Alex Poole,

1
Molto probabilmente DML (inserisci / elimina / aggiorna) anziché una query. E in un'altra sessione. Solo perché il ragazzo che ha chiesto sembra essere un principiante, la risposta potrebbe essere corretta. Ma NON PUOI impegnarti per conto di altri utenti in un sistema di produzione.
Arturo Hernandez,

4
Bene, ciò che mi ha fatto avere questo problema era in Toad: un collega era nella stessa tabella in cui ero io quando volevo cancellare una riga, e quindi non potevo eliminarlo. Quando è passato a un altro tavolo sono stato in grado di eliminare le righe. Forse aiuta qualcuno là fuori. Ma questo è solo se lavori con Toad all'interno delle tabelle e non per i querys.
DatRid

si è verificato di recente sul nostro server di gestione temporanea (applicazione Spring su WebSphere). La soluzione era quella di separare lo script di aggiornamento del database "monolitico" in parti più piccole spostando le istruzioni che causavano errori in un servizio di aggiornamento separato che utilizza una transazione separata: @Transactional (propagation = Propagation.REQUIRES_NEW)
actc

103

da qui ORA-00054: risorse occupate e acquisite con NOWAIT specificato

È inoltre possibile cercare sql, nome utente, macchina, informazioni sulla porta e accedere al processo effettivo che contiene la connessione

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
Ho dovuto rimuovere s.port dalla query ma mi ha permesso di trovare il colpevole
Sibster,

le serrature sono transitorie. quindi se arriva l'inserzione, ti impegni immediatamente. non verrà visualizzato in questa query. puoi ancora ottenere l'errore se emetti il ​​"DDL". mentre la transazione è aperta. vedi il mio post qui sotto. È davvero facile aggirare.
Bob,

4
Sto riscontrando lo stesso problema dell'OP, ma non riesco a vedere nessuna delle tabelle che menzioni (selezionare * da V $ LOCKED_OBJECT, ad esempio, restituisce ORA-00942: la tabella o la vista non esiste). Qualche idea?
random_forest_fanatic,

3
Potresti non avere privilegi sufficienti per guardare le viste di gestione.
njplumridge,

Seguito del S.Portproblema: i documenti 11.2 menzionano Portcome un campo in V$Session, ma per me, usando 11.1, S.Portnon è valido. È stato aggiunto per l'11.2, forse?

64

Si prega di uccidere Oracle Session

Utilizzare la query seguente per controllare le informazioni sulla sessione attiva

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;

uccidi come

alter system kill session 'SID,SERIAL#';

(Ad esempio alter system kill session '13,36543',;)

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


5
Dovrebbe avvertire questa risposta con quali privilegi sono richiesti. Ho CONNECTe RESOURCE, ma non quello che mi serve, con l'account che ho e dice ORA-00942: table or view does not exist. Non tutti coloro che leggono questa discussione avranno l' SYSaccount.
vapcguy,

Se aggiungi anche la colonna di selezione 'S.OSUSER' saprai quale utente stava eseguendo quella transazione e sarà utile nel caso in cui desideri verificare con l'utente prima di terminare la sessione.
Narasimha,

Se la sessione viene sospesa, il alter system kill session '13,36543'timeout verrà interrotto e la sessione non morirà. In tal caso, consultare: stackoverflow.com/a/24306610/587365
Andrew Spencer,

Durante l'inserimento dei dati in una tabella utilizzando un connection objectin pythonho ricevuto qualche errore. Quindi python scriptviene chiuso senza chiudere correttamente connection object. Ora ricevo l'errore "LOCKWAIT" quando provo a eliminare la tabella in un'altra sessione. Quando provo kill sessionnon ho abbastanza privilegi. Cos'altro si può fare per sbarazzarsi di questo?
sjd

17

C'è un modo molto semplice per ovviare a questo problema.

Se esegui una traccia 10046 sulla tua sessione (google questo ... troppo per spiegare). Vedrai che prima di qualsiasi operazione DDL Oracle esegue le seguenti operazioni:

BLOCCO TABELLA 'TABLE_NAME' NO ATTENDERE

Pertanto, se un'altra sessione ha una transazione aperta, viene visualizzato un errore. Quindi la soluzione è ... rullo di tamburi per favore. Rilascia il tuo lucchetto prima del DDL ed escludi "NO WAIT".

Nota speciale:

se stai facendo dividere / rilasciare le partizioni oracle blocca semplicemente la partizione. - Quindi puoi semplicemente bloccare la sottopartizione della partizione.

Quindi ... I seguenti passaggi risolvono il problema.

  1. LOCK TABLE 'NOME TABELLA'; - "Aspetterai" (gli sviluppatori chiamano questo impiccagione). fino alla sessione con la transazione aperta, si impegna. Questa è una coda. quindi potrebbero esserci diverse sessioni davanti a te. ma NON sbaglierai.
  2. Eseguire DDL. Il DDL eseguirà quindi un blocco con NO WAIT. Tuttavia, la sessione ha acquisito il blocco. Quindi sei bravo.
  3. Auto-commit DDL. Questo libera le serrature.

Le istruzioni DML "attenderanno" o come gli sviluppatori chiamano "blocco" mentre la tabella è bloccata.

Lo uso nel codice che viene eseguito da un lavoro per eliminare le partizioni. Funziona bene È in un database che si inserisce costantemente ad una velocità di diverse centinaia di inserti / secondo. Nessun errore

se ti stai chiedendo. In questo modo in 11g. L'ho già fatto in 10g prima e in passato.


3
ok, questo è sbagliato. in 11g, utilizzare set_ddl_timeout, disponibile solo in 11g. oracle esegue un commit prima di eseguire DDL, quindi rilascia il blocco. In 11g, puoi avere l'attesa DDL. Lo sto facendo ora. Funziona bene.
Bob,

3
in 11g dovresti usare LOCK TABLE table_name IN MODALITÀ ESCLUSIVA;
Kamil Roman,

1
Questo è davvero utile se stai ricevendo ORA-00054 da lavori batch, ma sospetto che la maggior parte delle persone che atterrano qui (incluso OP e io) stiano facendo un po 'di sviluppo e hanno lasciato aperta una sessione facendo inserimenti sullo stesso tavolo che " stai cercando di eliminare e ricreare. KILL SESSIONè la risposta giusta per queste persone.
Andrew Spencer,

@Bob Esempio di codice sia per 11g che per il vecchio modo sarebbe carino. A cosa serve la sintassi set_ddl_timeoute quale dovrebbe essere?
vapcguy,

1
@vapcguy ha funzionato per me su 11g: ALTER SYSTEM SET ddl_lock_timeout=20;vedi documenti
rshdev,

13

Questo errore si verifica quando la risorsa è occupata. Controlla se ci sono vincoli referenziali nella query. O anche le tabelle menzionate nella query potrebbero essere occupate. Potrebbero essere coinvolti in qualche altro lavoro che sarà sicuramente elencato nei seguenti risultati della query:

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

Trova il SID,

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

1
Non tutti avranno accesso a queste visualizzazioni. Ho capito ORA-00942: table or view does not exist.
vapcguy,

In tali casi, DB Admins è responsabile della fornitura di tali informazioni.
Arunchunaivendan,

Non sempre. Ho dovuto provare a far capire il codice e aggirare il problema, e né io né il mio account di servizio avremo questi diritti.
vapcguy,

7

Ciò accade quando una sessione diversa da quella utilizzata per modificare una tabella è in possesso di un blocco probabilmente a causa di un DML (aggiornamento / eliminazione / inserimento). Se stai sviluppando un nuovo sistema, è probabile che tu o qualcuno del tuo team rilasci la dichiarazione di aggiornamento e che sia possibile interrompere la sessione senza molte conseguenze. Oppure puoi impegnarti da quella sessione una volta che sai chi ha la sessione aperta.

Se hai accesso a un sistema di amministrazione SQL, utilizzalo per trovare la sessione offensiva. E forse ucciderlo.

Potresti usare v $ session e v $ lock e altri, ma ti suggerisco di google come trovare quella sessione e come ucciderla.

In un sistema di produzione, dipende davvero. Per Oracle 10g e oltre, potresti eseguire

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

In una sessione separata, ma tieni pronto quanto segue nel caso in cui impieghi troppo tempo.

alter system kill session '....

Dipende dal sistema che hai, è più probabile che i sistemi più vecchi non si impegnino ogni volta. Questo è un problema poiché potrebbero esserci blocchi di vecchia data. Quindi il tuo blocco impedirebbe qualsiasi nuovo blocco e aspetterebbe un blocco che sa quando verrà rilasciato. Ecco perché hai l'altra affermazione pronta. Oppure potresti cercare script PLSQL là fuori che fanno automaticamente cose simili.

Nella versione 11g è presente una nuova variabile d'ambiente che imposta un tempo di attesa. Penso che probabilmente faccia qualcosa di simile a quello che ho descritto. Intendiamoci che i problemi di blocco non vanno via.

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

Infine, potrebbe essere meglio attendere fino a quando non ci sono pochi utenti nel sistema per eseguire questo tipo di manutenzione.


E come scopri la sessione da uccidere alter system kill session '....se non hai accesso alle viste di gestione?
vapcguy,

Che non lo so.
Arturo Hernandez,

7

Nel mio caso, ero abbastanza sicuro che fosse una delle mie sessioni a bloccare. Pertanto, è stato sicuro eseguire le seguenti operazioni:

  • Ho trovato la sessione offensiva con:

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

    La sessione era inattiva , ma in qualche modo manteneva il blocco. Tieni presente che potrebbe essere necessario utilizzare alcune altre condizioni WHERE nel tuo caso (ad es. Try USERNAMEo MACHINEfields).

  • Ha ucciso la sessione usando il IDe SERIAL#acquisito sopra:

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

A cura di @thermz: se nessuna delle precedenti query a sessione aperta funziona, prova questa. Questa query può aiutarti a evitare errori di sintassi durante l'uccisione delle sessioni:

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

Se nessuna delle precedenti query a sessione aperta funziona, prova questa.
thermz,

5

Basta controllare il processo che tiene la sessione e ucciderlo. È tornato alla normalità.

Sotto SQL troverai il tuo 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;

Quindi uccidilo

ALTER SYSTEM KILL SESSION 'sid,serial#'

O

alcuni esempi che ho trovato online sembrano aver bisogno dell'ID dell'istanza e di modificare la sessione di interruzione del 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

Sono riuscito a colpire questo errore semplicemente creando una tabella! Non c'era ovviamente alcun problema di contesa su un tavolo che non esisteva ancora. L' CREATE TABLEistruzione conteneva una CONSTRAINT fk_name FOREIGN KEYclausola che faceva riferimento a una tabella ben popolata. Dovevo:

  • Rimuovere la clausola FOREIGN KEY dall'istruzione CREATE TABLE
  • Crea un INDICE nella colonna FK
  • Crea l'FK

Ho appena avuto lo stesso problema. Sono stato in grado di creare la tabella dopo aver rimosso la definizione di fk dall'istruzione ddl, ma non riesco ad aggiungerla anche dopo aver creato l'indice sulla colonna.
vadipp,

Sono stato in grado di risolverlo. Innanzitutto, ho aggiunto una novalidateclausola al alter table add constraint. Questo in qualche modo lo lascia correre, ma si blocca. Quindi ho guardato i blocchi della sessione per scoprire in quale sessione si blocca. E poi ho ucciso quella sessione.
vadipp,

3

Ho avuto questo errore accadere quando avevo 2 script che stavo eseguendo. Avevo:

  • Una sessione SQL * Plus connessa direttamente tramite un account utente dello schema (account n. 1)
  • Un'altra sessione SQL * Plus si è connessa utilizzando un altro account utente dello schema (account n. 2), ma si è collegata attraverso un collegamento al database come primo account

Ho eseguito un drop della tabella, quindi la creazione della tabella come account n. 1. Ho eseguito un aggiornamento della tabella nella sessione dell'account n. 2. Non è stato eseguito il commit delle modifiche. Rieseguito script di eliminazione / creazione della tabella come account n. 1. Errore nel drop table xcomando.

L'ho risolto eseguendo COMMIT;nella sessione SQL * Plus dell'account n. 2.


Se non disponi delle autorizzazioni per eliminare una tabella, cosa farai? Risposta
errata

1
Shakeer, quello era solo un esempio di quello che stavo facendo quando mi è successo - non la soluzione al problema - che era nella mia ultima riga - che eseguiva a COMMIT;. Se non riesci nemmeno a eliminare una tabella, non hai i permessi per modificare tutto ciò che potrebbe farti entrare in questo problema in primo luogo.
vapcguy,

-2

Devo anche affrontare il problema simile. Niente programmatore deve fare per risolvere questo errore. Ho informato il mio team DBA di Oracle. Uccidono la sessione e hanno funzionato come un fascino.


1
Qualcuno deve ancora fare qualcosa. Cosa succede se il team DBA non sa cosa fare e come uccidere una sessione? Cattiva risposta.
vapcguy,

1
Se DBA non sa come uccidere la sessione, allora non è in grado di lavorare
Shakeer Hussain,

Tutti hanno bisogno di un aggiornamento sulla sintassi di volta in volta per evitare di sbagliare.
vapcguy,

-5

La soluzione fornita dal link di Shashi è la migliore ... non c'è bisogno di contattare dba o qualcun altro

fare un backup

create table xxxx_backup as select * from xxxx;

elimina tutte le righe

delete from xxxx;
commit;

inserisci il tuo backup.

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

10
elimina / tronca non sono intercambiabili. l'esecuzione di un numero elevato di eliminazioni ha enormi implicazioni in termini di prestazioni. Questo è davvero brutto.
Bob,

Ho pensato che questo fosse un modello comune.
Shawn Xue,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.