ORA-00054: zasoby zajęte i pobieranie z określonym NOWAIT lub upłynął limit czasu

193

Dlaczego pojawia się ten błąd bazy danych podczas aktualizacji tabeli?

BŁĄD w wierszu 1: ORA-00054: zajęty zasób i pobieranie z określonym NOWAIT lub upłynął limit czasu

słońce
źródło
22
Ogólnie pomaga, jeśli opublikujesz oświadczenie, które prowadzi do błędu
Gary Myers

Odpowiedzi:

222

Twoja tabela jest już zablokowana przez jakieś zapytanie. Na przykład możliwe, że wykonałeś polecenie „wybierz do aktualizacji” i jeszcze nie zatwierdziłeś / wycofałeś i uruchomiłeś inne zapytanie wyboru. Wykonaj zatwierdzenie / wycofanie przed wykonaniem zapytania.

użytkownik258367
źródło
47
Dodałbym do tego „w innej sesji”. Jednym z typowych scenariuszy jest przetestowanie aktualizacji w narzędziu, na przykład SQL Developer lub Toad, a następnie próba uruchomienia jej w innym miejscu, podczas gdy pierwsza sesja nadal trzyma blokadę. Musisz więc zatwierdzić / przywrócić drugą sesję, zanim będziesz mógł ponownie uruchomić aktualizację.
Alex Poole,
1
Najprawdopodobniej DML (wstaw / usuń / aktualizuj) zamiast zapytania. I w innej sesji. Tylko dlatego, że facet, który zapytał, wydaje się być nowicjuszem, odpowiedź może być poprawna. Ale NIE MOŻESZ zatwierdzić w imieniu innych użytkowników w systemie produkcyjnym.
Arturo Hernandez
4
Cóż, to, co sprawiło, że miałem ten problem, było w Toad: kolega był w tej samej tabeli, co ja, kiedy chciałem usunąć wiersz, więc nie mogłem go usunąć. Kiedy przeszedł do innej tabeli, mogłem usunąć wiersze. Może pomóc komuś tam. Ale dzieje się tak tylko wtedy, gdy pracujesz z Toadem wewnątrz tabel, a nie dla zapytań.
DatRid
ostatnio wystąpił na naszym serwerze pomostowym (aplikacja Spring na WebSphere). Rozwiązaniem było podzielenie „monolitycznego” skryptu aktualizacji bazy danych na mniejsze części poprzez przeniesienie powodujących błędy instrukcji do oddzielnej usługi aktualizacji, która korzysta z oddzielnej transakcji: @Transactional (propagation = Propagation.REQUIRES_NEW)
akt
103

stąd ORA-00054: zasoby zajęte i pozyskiwanie ze wskazanym NOWAIT

Możesz także sprawdzić dane SQL, nazwę użytkownika, komputer, port i przejść do faktycznego procesu, który utrzymuje połączenie

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;
Abey Tom
źródło
5
Musiałem usunąć s.port z zapytania, ale pozwoliło mi to znaleźć winowajcę
Sibster
zamki są przejściowe. więc jeśli wstawka jest dostarczana, natychmiast zatwierdzasz. nie pojawi się w tym zapytaniu. nadal możesz otrzymać błąd, jeśli wydasz „DDL”. podczas gdy transakcja jest otwarta. zobacz mój post poniżej. To jest naprawdę łatwe do obejścia.
Bob
4
Mam ten sam problem co OP, ale nie widzę żadnej z wymienionych tabel (wybierz * z V $ LOCKED_OBJECT, na przykład zwraca ORA-00942: tabela lub widok nie istnieje). Jakieś pomysły?
random_forest_fanatic
3
Możesz nie mieć wystarczających uprawnień do przeglądania widoków zarządzania.
njplumridge
Działania następcze w związku z S.Portproblemem: dokumenty 11.2 wspominają Portjako pole w V$Session, ale dla mnie używanie 11.1 S.Portjest nieprawidłowe. Może został dodany do wersji 11.2?
64

Proszę zabić Oracle Session

Użyj poniższego zapytania, aby sprawdzić informacje o aktywnej sesji

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;

zabij jak

alter system kill session 'SID,SERIAL#';

(Na przykład alter system kill session '13,36543';)

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

Chan Myae Thu
źródło
5
Należy zastrzec tę odpowiedź z wymaganymi uprawnieniami. Mam CONNECTiRESOURCE , ale nie cokolwiek tego potrzebuje, z kontem, które mam i mówi ORA-00942: table or view does not exist. Nie wszyscy czytający ten wątek będą mieli SYSkonto.
vapcguy
Jeśli dodasz również wybraną kolumnę „S.OSUSER”, będziesz wiedział, który użytkownik uruchomił tę transakcję, i będzie to przydatne na wypadek, gdybyś chciał skontaktować się z użytkownikiem przed zabiciem sesji.
Narasimha,
Jeśli sesja zostanie zawieszona, alter system kill session '13,36543'upłynie limit czasu i sesja nie umrze. W takim przypadku patrz: stackoverflow.com/a/24306610/587365
Andrew Spencer
Podczas wstawiania danych do tabeli za pomocą connection objectin pythonwystąpił błąd. Następnie python scriptzamknie się bez prawidłowego zamknięcia connection object. Teraz pojawia się błąd „LOCKWAIT”, gdy próbuję upuścić tabelę w innej sesji. Kiedy próbuję, kill sessionnie mam wystarczających uprawnień. Co jeszcze można zrobić, aby się tego pozbyć?
sjd
17

Rozwiązanie tego problemu jest bardzo łatwe.

Jeśli w sesji uruchomisz śledzenie 10046 (google to ... za dużo, by to wyjaśnić). Zobaczysz, że przed każdą operacją DDL Oracle wykonuje następujące czynności:

ZABLOKUJ TABELĘ „TABLE_NAME” BEZ CZEKAJ

Więc jeśli inna sesja ma otwartą transakcję, pojawi się błąd. Więc poprawka polega na ... bębnie, proszę. Wydaj własną blokadę przed DDL i pomiń „BRAK OCZEKIWANIA”.

Specjalna notatka:

jeśli wykonujesz dzielenie / upuszczanie partycji, Oracle blokuje partycję. - więc możesz po prostu zablokować partycję partycji.

Więc ... Poniższe kroki rozwiązują problem.

  1. BLOKADA TABELI „NAZWA TABELI”; - będziesz „czekać” (programiści nazywają to zawieszanie). aż do sesji z otwartą transakcją, zatwierdza. To jest kolejka. więc może być kilka sesji przed tobą. ale NIE popełnisz błędu.
  2. Wykonaj DDL. Twój DDL uruchomi wtedy blokadę BEZ OCZEKIWANIA. Jednak twoja sesja uzyskała blokadę. Więc jesteś dobry
  3. Automatyczne zatwierdzanie DDL. Uwalnia to zamki.

Instrukcje DML będą „czekać” lub, jak programiści nazywają to „zawieszeniem”, gdy tabela jest zablokowana.

Używam tego w kodzie, który uruchamia się z zadania, aby usunąć partycje. To działa dobrze. Znajduje się w bazie danych, która ciągle wstawia w tempie kilkuset wstawień na sekundę. Bez błędów.

jeśli się zastanawiasz. Robi to w 11g. Zrobiłem to już wcześniej w 10 g.

Pion
źródło
3
ok, to jest złe w 11g użyj set_ddl_timeout, ta opcja jest dostępna tylko w 11g. oracle dokonuje zatwierdzenia przed wykonaniem DDL, więc zwalnia blokadę. W 11g możesz czekać na DDL. Robię to teraz. Działa w porządku.
Bob
3
w 11g powinieneś użyć LOCK TABLE nazwa_tabeli W TRYBIE WYŁĄCZNYM;
Kamil Roman
1
Jest to bardzo przydatne, jeśli otrzymujesz ORA-00054 z zadań wsadowych, ale podejrzewam, że większość osób lądujących tutaj (w tym OP i ja) robi pewne prace rozwojowe i pozostawiła otwartą sesję, robiąc wstawki na tym samym stole, który „ próbuję upuścić i odtworzyć. KILL SESSIONjest właściwą odpowiedzią dla tych ludzi.
Andrew Spencer,
@Bob Przykładowy kod zarówno dla 11g, jak i starego sposobu byłby miły. Jaka jest składnia set_ddl_timeouti jaka powinna być?
vapcguy
1
@vapcguy to działało dla mnie na 11g: ALTER SYSTEM SET ddl_lock_timeout=20;patrz dokumenty
rshdev
13

Ten błąd występuje, gdy zasób jest zajęty. Sprawdź, czy w zapytaniu występują ograniczenia referencyjne. Lub nawet tabele wymienione w zapytaniu mogą być zajęte. Mogą być zaangażowani w jakieś inne zadanie, które zostanie zdecydowanie wymienione w następujących wynikach zapytania:

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

Znajdź SID,

SELECT * FROM V$OPEN_CURSOR WHERE SID = --the id
Arunchunaivendan
źródło
1
Nie wszyscy będą mieli dostęp do tych widoków. I dostać ORA-00942: table or view does not exist.
vapcguy
W takich przypadkach administratorzy DB są odpowiedzialni za dostarczenie tych informacji.
Arunchunaivendan
Nie zawsze. Musiałem spróbować to rozszyfrować i obejść ten kod, i ani ja, ani moje konto usługi nie będą mieć tych praw.
vapcguy
7

Dzieje się tak, gdy sesja inna niż ta używana do zmiany tabeli trzyma blokadę prawdopodobnie z powodu DML (aktualizacja / usuwanie / wstawianie). Jeśli opracowujesz nowy system, prawdopodobne jest, że ty lub ktoś z twojego zespołu wyda instrukcję aktualizacji i możesz zakończyć sesję bez większych konsekwencji. Lub możesz zatwierdzić z tej sesji, gdy wiesz, kto ma otwartą sesję.

Jeśli masz dostęp do systemu administracyjnego SQL, użyj go do znalezienia obraźliwej sesji. I może to zabijesz.

Możesz użyć sesji v $ i blokady v $ i innych, ale sugeruję, aby google znaleźć tę sesję, a następnie ją zabić.

W systemie produkcyjnym to naprawdę zależy. Dla wyroczni 10g i starszych możesz wykonać

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

W osobnej sesji, ale przygotuj następujące na wypadek, gdyby trwało to zbyt długo.

alter system kill session '....

Zależy to od posiadanego systemu, starsze systemy częściej nie zatwierdzają się za każdym razem. Jest to problem, ponieważ mogą istnieć długo stojące zamki. Twoja blokada zapobiegnie nowym blokadom i zaczeka na blokadę, która wie, kiedy zostanie zwolniona. Dlatego masz przygotowane inne oświadczenie. Możesz też poszukać skryptów PLSQL, które automatycznie robią podobne rzeczy.

W wersji 11g dostępna jest nowa zmienna środowiskowa, która ustawia czas oczekiwania. Myślę, że prawdopodobnie robi coś podobnego do tego, co opisałem. Pamiętaj, że problemy z blokowaniem nie znikają.

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

Wreszcie najlepiej może poczekać, aż w systemie będzie niewielu użytkowników wykonujących tego rodzaju czynności konserwacyjne.

Arturo Hernandez
źródło
Jak znaleźć sesję, dla której chcesz zabić, alter system kill session '....jeśli nie masz dostępu do widoków zarządzania?
vapcguy
Tego nie wiem.
Arturo Hernandez
7

W moim przypadku byłem całkiem pewien, że to jedna z moich sesji, która blokowała. Dlatego bezpieczne było wykonanie następujących czynności:

  • Znalazłem obraźliwą sesję z:

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

    Sesja była nieaktywna , ale nadal jakoś utrzymywała blokadę. Pamiętaj, że w twoim przypadku może być konieczne zastosowanie innego warunku GDZIE (np. Try USERNAMElub MACHINEpola).

  • Zabił sesję przy użyciu IDi SERIAL#nabytych powyżej:

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

Edytowane przez @thermz: Jeśli żadne z poprzednich zapytań otwartych sesji nie działa, spróbuj tego. To zapytanie może pomóc uniknąć błędów składniowych podczas zabijania sesji:

  • SELECT 'ALTER SYSTEM KILL SESSION '''||SID||','||SERIAL#||''' immediate;' FROM V$SESSION WHERE OSUSER='my_local_username_on_OS'
wrygiel
źródło
Jeśli żadne z poprzednich zapytań otwartych sesji nie działa, wypróbuj to.
thermz
5

Po prostu sprawdź proces wstrzymujący sesję i zabij ją. Wrócił do normy.

Poniżej SQL znajdziesz swój proces

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;

Więc zabij to

ALTER SYSTEM KILL SESSION 'sid,serial#'

LUB

jakiś przykład, który znalazłem online, wydaje się, że potrzebuje identyfikatora instancji, a także zmienia sesję zabijania systemu „130,620, @ 1”;

Mathavan John
źródło
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#';

harun ugur
źródło
3

Udało mi się trafić w ten błąd po prostu tworząc tabelę! Oczywiście na stole, który jeszcze nie istniał, nie było problemu z rywalizacją. CREATE TABLEOświadczenie zawierało CONSTRAINT fk_name FOREIGN KEYklauzulę przedstawieniu dobrze zaludnionych tabeli. Musiałem:

  • Usuń klauzulę FOREIGN KEY z instrukcji CREATE TABLE
  • Utwórz INDEKS w kolumnie FK
  • Utwórz FK
bwperrin
źródło
Właśnie miałem ten sam problem. Byłem w stanie utworzyć tabelę po usunięciu definicji fk z instrukcji ddl, ale nie mogę jej dodać nawet po utworzeniu indeksu w kolumnie.
vadipp,
Byłem w stanie to rozwiązać. Najpierw dodałem novalidateklauzulę do alter table add constraint. To w jakiś sposób pozwala mu działać, ale blokuje się. Potem spojrzałem na blokady sesji, aby dowiedzieć się, na której sesji blokuje. A potem zabiłem tę sesję.
vadipp,
3

Miałem ten błąd, gdy miałem 2 uruchomione skrypty. Miałem:

  • Sesja SQL * Plus połączona bezpośrednio przy użyciu konta użytkownika schematu (konto nr 1)
  • Kolejna sesja SQL * Plus połączona przy użyciu innego konta użytkownika schematu (konto nr 2), ale łączenie się przez łącze bazy danych jako pierwsze konto

Uruchomiłem zrzut tabeli, a następnie utworzenie tabeli jako konto nr 1. Przeprowadziłem aktualizację tabeli na sesji konta nr 2. Nie zatwierdził zmian. Ponownie uruchom skrypt upuszczania / tworzenia tabeli jako konto nr 1. Wystąpił błąd wdrop table x polecenia.

Rozwiązałem go, uruchamiając COMMIT;sesję SQL * Plus konta nr 2.

vapcguy
źródło
Jeśli nie masz uprawnień do upuszczenia tabeli, co będziesz robić? Zła odpowiedź
Shakeer Hussain
1
Shakeer, to był tylko przykład tego, co robiłem, kiedy mi się przydarzyło - nie rozwiązanie problemu - który był w mojej ostatniej linii - uruchomienie COMMIT;. Jeśli nie możesz nawet upuścić stołu, nie masz uprawnień do zmiany czegokolwiek, co doprowadziłoby Cię do tego problemu.
vapcguy
-2

Mam również podobny problem. Nic nie musi robić programista, aby rozwiązać ten błąd. Poinformowałem mój zespół Oracle DBA. Zabijają sesję i działają jak urok.

Shakeer Hussain
źródło
1
Ktoś wciąż musi coś zrobić. Co jeśli zespół DBA nie wie, co robić i jak zabić sesję? Zła odpowiedź.
vapcguy
1
Jeśli DBA nie wie, jak zabić sesję, to nie nadaje się do pracy
Shakeer Hussain
Każdy potrzebuje od czasu do czasu odświeżenia składni, aby uniknąć pomyłki.
vapcguy
-5

Rozwiązanie podane przez link Shashi jest najlepsze ... nie trzeba kontaktować się z dba lub kimś innym

zrób kopię zapasową

create table xxxx_backup as select * from xxxx;

usuń wszystkie wiersze

delete from xxxx;
commit;

włóż kopię zapasową.

insert into xxxx (select * from xxxx_backup);
commit;
tafibo
źródło
10
delete / truncate nie są wymienne. wykonywanie dużej liczby operacji usuwania ma ogromny wpływ na wydajność. To jest naprawdę złe.
Bob
Myślałem, że jest to powszechny wzór.
Shawn Xue