ORA-00054: ресурс зайнятий та набувається з вказаним NOWAIT або минув термін очікування


193

Чому я отримую цю помилку бази даних під час оновлення таблиці?

ПОМИЛКА в рядку 1: ORA-00054: ресурс зайнятий та придбаний із вказаним NOWAIT або закінчився час закінчення


22
Зазвичай це допомагає, якщо ви опублікуєте заяву, яка призводить до помилки
Gary Myers

Відповіді:


222

Ваша таблиця вже заблокована запитом. Наприклад, ви, можливо, виконали "select for update" і ще не здійснили / відкотили та не запустили інший запит вибору. Зробіть комісію / відкат перед виконанням запиту.


47
До цього я б додав "на іншому сеансі". Один спільний сценарій полягає в тому, що ви протестували оновлення в інструменті, скажімо, SQL Developer або Toad, а потім спробували запустити його деінде, поки перший сеанс все ще містить блокування. Таким чином, вам потрібно здійснити / відкатати інший сеанс, перш ніж знову запустити оновлення.
Алекс Пул

1
Швидше за все DML (вставити / видалити / оновити), а не запит. І в інший сеанс. Просто тому, що хлопець, який запитував, здається, новачок, відповідь може бути правильною. Але ви НЕ МОЖЕТЕ взяти на себе зобов'язання від інших користувачів у виробничій системі.
Артуро Ернандес

4
Що ж, у мене ця проблема була в Жабі: Колега був у тій самій таблиці, що і я, коли я хотів видалити рядок, і тому я не міг її видалити. Коли він перейшов на іншу таблицю, я зміг видалити рядки. Можливо, комусь там допоможе. Але це лише в тому випадку, якщо ви працюєте з Toad всередині таблиць, а не для querys.
DatRid

нещодавно відбувся на нашому сервері інсценування (Spring-додаток на WebSphere). Рішенням було розділити "монолітний" скрипт оновлення бази даних на більш дрібні фрагменти, перемістивши заяви, що викликають помилки, в окрему службу оновлення, яка використовує окрему транзакцію: @Transactional (propagation = Propagation.REQUIRES_NEW)
actc

103

звідси 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

замки минущі. тож якщо вставка приходить, ви здійснюєте негайно. він не відображатиметься в цьому запиті. ви все одно можете отримати помилку, якщо ви видасте "DDL". поки транзакція відкрита. дивіться мою посаду нижче. Це справді легко пройти.
Боб

4
У мене така ж проблема, що і в ОП, але я не бачу жодної з згаданих вами таблиць (наприклад, виберіть * з V $ LOCKED_OBJECT, наприклад, повертається ORA-00942: таблиця або перегляд не існує). Будь-які ідеї?
random_forest_fanatic

3
У вас може бути недостатньо привілеїв для перегляду поглядів управління.
njplumridge

Подальше вирішення S.Portпроблеми: 11.2 документа згадується Portяк поле в V$Session, але для мене, використовуючи 11.1, S.Portнедійсне. Це було додано за 11,2, можливо?

64

Будь ласка, вбийте сеанс 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
Слід відповісти на цю відповідь, які привілеї потрібні. У мене є CONNECTі RESOURCE, але не б це потреба, з урахуванням у мене є, і каже ORA-00942: table or view does not exist. Не всі, хто читає цю тему, матимуть SYSобліковий запис.
vapcguy

Якщо ви також додасте стовпчик "S.OSUSER", ви дізнаєтесь, який користувач виконував цю транзакцію, і це буде зручно в тому випадку, якщо ви хочете проконсультуватися з користувачем перед тим, як вбити сеанс.
Нарасимха

Якщо сеанс буде вимкнено, то час alter system kill session '13,36543'закінчиться, і сеанс не загине. У цьому випадку дивіться: stackoverflow.com/a/24306610/587365
Ендрю Спенсер

При вставці даних в таблицю з використанням connection objectв pythonя отримав деяку помилку. Потім python scriptзакривається, не закриваючи належним чином connection object. Тепер я отримую помилку "LOCKWAIT", коли я намагаюся скинути таблицю в інший сеанс. Коли я намагаюся, kill sessionмені не вистачає привілеї. Що ще можна зробити, щоб позбутися цього?
SJD

17

Існує дуже легка робота з цією проблемою.

Якщо ви запустите 10046 слід у своєму сеансі (Google це ... занадто багато для пояснення). Ви побачите, що перед будь-якою операцією DDL Oracle робить наступне:

ЗАКЛЮЧЕНИЙ СТОЛ "TABLE_NAME" НЕ ЗАЧЕКАЙТЕ

Отже, якщо інший сеанс має відкриту транзакцію, ви отримуєте помилку. Тож виправлення полягає в ... барабанному рулоні, будь ласка. Оформіть свій власний замок перед DDL та залиште «НЕ ЗАЧЕКАЙТЕ».

Спеціальна примітка:

якщо ви робите розбиття / випадання розділів, оракул просто блокує розділ. - так що ви можете просто заблокувати підрозділ розділу.

Отже ... Наступні кроки вирішують проблему.

  1. БЛОК ТАБЛИЦІ «ІМ’Я СТОЛЯ»; - ви будете "чекати" (розробники називають це висячим). до сеансу з відкритою транзакцією. Це черга. тому перед вами може бути кілька сеансів. але ви НЕ помилитесь
  2. Виконати DDL. Потім ваш DDL запустить блокування з НЕ ЗАЧЕКАЙТЕ. Однак ваш сеанс отримав блокування. Значить, ти добрий.
  3. DDL автоматично здійснює комісію. Це звільняє замки.

Висловлювання DML будуть "чекати" або як розробники називають це "висіти", коли таблиця заблокована.

Я використовую це в коді, який працює від завдання для скидання розділів. Це чудово працює. Він знаходиться в базі даних, яка постійно вставляється зі швидкістю в кілька сотень вставок / секунду. Немає помилок.

якщо вам цікаво Роблячи це в 11г. Я робив це за 10 г раніше, як і раніше.


3
ок, це неправильно. в 11 г, використовуйте set_ddl_timeout. Це доступно лише в 11 г. Oracle виконує зобов’язання перед тим, як робити DDL, тому він звільняє замок. У 11 г ви можете зачекати DDL. Я зараз цим займаюся. Добре працює.
Боб

3
в 11 г слід використовувати ВІДКЛЮЧЕННЯ ТАБЛИЧНОГО ТАБЛИЦЯ В ЕКСКЛЮЗИВНОМУ РЕЖИМІ;
Каміль Роман

1
Це дуже корисно, якщо ви отримуєте ORA-00054 з пакетних завдань, але я підозрюю, що більшість людей, які приземляються сюди (включаючи ОП, і я), роблять певну розробку і залишили сесію відкритою, роблячи вставки в тій самій таблиці, яку вони ' Ви намагаєтеся кинути і відтворити. KILL SESSIONє правильною відповіддю для цих людей.
Ендрю Спенсер

@Bob Приклад коду як для 11г, так і для старого способу було б непогано. Що таке синтаксис set_ddl_timeoutі яким він повинен бути?
vapcguy

1
@vapcguy це працювало для мене 11 г: 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 10 г і більше ви можете виконати

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

Що я не знаю.
Артуро Ернандес

7

У моєму випадку я був повністю впевнений, що це була одна з моїх власних сесій, яка блокувала. Тому було безпечно зробити наступне:

  • Я виявив сеанс, що порушує:

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

    Сеанс був неактивним , але все одно якимось чином тримав замок. Зауважте, що вам може знадобитися використовувати інший стан WHERE у вашому випадку (наприклад, спробуйте USERNAMEабо MACHINEполя).

  • Убив сеанс, використовуючи 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#'

АБО

деякий приклад, який я знайшов в Інтернеті, здається, потребує ідентифікатора екземпляра, а також зміни сеансу вбивства системи "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пункт посилання добре населеної таблицю. Мені довелося:

  • Вийміть пункт FOREIGN KEY з оператора CREATE TABLE
  • Створіть INDEX у стовпці FK
  • Створіть ФК

У мене просто була така ж проблема. Я зміг створити таблицю після того, як я видалив визначення fk з заяви ddl, але я не в змозі додати його навіть після того, як я створив індекс у стовпці.
vadipp

Я зміг це вирішити. По-перше, я додав novalidateпункт до alter table add constraint. Це якимось чином дозволяє йому працювати, але воно блокується. Потім я переглянув блокування сеансу, щоб з’ясувати, на якому сеансі він заблокований. І тоді я вбив сесію.
vadipp

3

У мене була така помилка, коли у мене було 2 сценарії, якими я працював. Я мав:

  • Сеанс SQL * Plus, підключений безпосередньо за допомогою облікового запису користувача схеми (рахунок №1)
  • Ще один сеанс SQL * Plus, підключений за допомогою іншого облікового запису користувача (рахунок №2), але підключення через посилання бази даних як перший рахунок

Я запустив таблицю краплі, а потім створення таблиці як рахунок №1. Я провів оновлення таблиці в сеансі №2 акаунта. Зміни не здійснили. Повторно застосував сценарій падіння / створення таблиці як рахунок №1. У drop table xкоманді з’явилася помилка .

Я вирішив це, запустивши COMMIT;в сеанс SQL * Plus облікового запису №2.


Якщо у вас немає дозволів на викидання таблиці, то що ви будете робити? Погана відповідь
Шейкер Хуссей

1
Шейкер, це був лише приклад того, що я робив, коли це сталося зі мною - не рішення проблеми - що було в моєму останньому рядку - запуск а COMMIT;. Якщо ви навіть не можете опустити таблицю, ви не маєте дозволу змінювати будь-що, що спонукало б вас до цього питання.
vapcguy

-2

Я також стикаюся з подібним випуском. Нічого програміст не повинен зробити, щоб усунути цю помилку. Я повідомив свою команду Oracle DBA. Вони вбивають сеанс і спрацьовують як зачарування.


1
Хтось ще повинен щось робити. Що робити, якщо команда DBA не знає, що робити, і як вбити сеанс? Погана відповідь.
vapcguy

1
Якщо DBA не знає, як вбити сеанс, то він непридатний для роботи
Шейкер Хуссей

Кожен час від часу потребує оновлення синтаксису, щоб уникнути помилок.
vapcguy

-5

Рішення, яке надається посиланням Шаші, є найкращим ... не потрібно контактувати з dba чи кимось іншим

зробити резервну копію

create table xxxx_backup as select * from xxxx;

видалити всі рядки

delete from xxxx;
commit;

вставити резервну копію.

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

10
видалення / обрізання не є взаємозамінними. виконання великої кількості делетів має величезні наслідки для продуктивності. Це справді погано.
Боб

Я думав, що це звичайна закономірність.
Шон Сюе
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.