ORA-00054: ресурс занят и получен с указанным значением NOWAIT или истекло время ожидания - PullRequest
160 голосов
/ 30 января 2011

Почему я получаю эту ошибку базы данных при обновлении таблицы?

ОШИБКА в строке 1: ORA-00054: ресурс занят и получен с указанным значением NOWAIT или истекло время ожидания

Ответы [ 13 ]

191 голосов
/ 30 января 2011

Ваша таблица уже заблокирована каким-либо запросом. Например, вы, возможно, выполнили команду «выбрать для обновления», но еще не зафиксировали / откатили и не запустили еще один запрос на выборку. Сделайте коммит / откат перед выполнением запроса.

85 голосов
/ 10 августа 2012

отсюда 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;
52 голосов
/ 10 февраля 2014

Пожалуйста, убейте Oracle Session

Используйте приведенный ниже запрос для проверки информации активного сеанса

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;

kill как

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

16 голосов
/ 30 апреля 2013

Существует очень легко обойти эту проблему.

Если вы выполняете трассировку 10046 в своем сеансе (Google это ... слишком много, чтобы объяснить).Вы увидите, что перед любой операцией DDL Oracle делает следующее:

LOCK TABLE 'TABLE_NAME' NO WAIT

Так что, если в другом сеансе есть открытая транзакция, вы получите ошибку.Так что исправить это ... барабанная дробь, пожалуйста.Создайте свой собственный замок перед DDL и пропустите «НЕ ПОДОЖДИТЕ».

Специальное примечание:

, если вы делаете разбиение / удаление разделов, oracle просто блокирует раздел.- так что вы можете просто заблокировать подраздел раздела.

Итак ... Следующие шаги решают проблему.

  1. LOCK TABLE 'TABLE NAME';- вы будете «ждать» (разработчики называют это зависанием).до сеанса с открытой транзакцией, фиксирует.Это очередь.так что может быть несколько сессий впереди вас.но вы не ошибетесь.
  2. Выполнить DDL.Затем ваш DDL запустит блокировку без ожидания.Тем не менее, ваша сессия приобрела замок.Так что вы хороши.
  3. DDL автокоммитов.Это освобождает блокировки.

Операторы DML будут «ждать» или, как разработчики называют их «зависать», пока таблица заблокирована.

Я использую это в коде, который запускается из задания для удаления разделов.Работает нормально.Он находится в базе данных, которая постоянно вставляется со скоростью несколько сотен вставок в секунду.Нет ошибок

если вам интересно.Делать это в 11г.Я делал это в 10g и раньше, и раньше.

9 голосов
/ 15 июля 2013

Эта ошибка возникает, когда ресурс занят.Проверьте, есть ли у вас ссылочные ограничения в запросе.Или даже таблицы, которые вы упомянули в запросе, могут быть заняты.Они могут быть заняты другой работой, которая обязательно будет указана в следующих результатах запроса:

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

Найти SID,

SELECT * FROM V$OPEN_CURSOR WHERE SID = --the id
7 голосов
/ 03 сентября 2013

В моем случае я был совершенно уверен, что это была одна из моих сессий , которая блокировала.Таким образом, было безопасно сделать следующее:

  • Я обнаружил сессию, вызвавшую ошибку:неактивен , но все равно как-то удерживал блокировку.Обратите внимание, что вам может понадобиться использовать какое-то другое условие 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'
6 голосов
/ 15 июля 2013

Это происходит, когда сеанс, отличный от сеанса, используемого для изменения таблицы, удерживает блокировку, вероятно, из-за DML (обновление / удаление / вставка). Если вы разрабатываете новую систему, вполне вероятно, что вы или кто-то из вашей команды выдает оператор обновления, и вы можете прервать сеанс без особых последствий. Или вы можете выполнить фиксацию из этого сеанса, когда узнаете, у кого открыт сеанс.

Если у вас есть доступ к системе администратора SQL, используйте ее, чтобы найти нарушающий сеанс. И, возможно, убить его.

Вы можете использовать v $ session и v $ lock и другие, но я предлагаю вам Google, как найти этот сеанс, а затем как его убить.

В производственной системе это действительно зависит. Для оракула 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);

Наконец, возможно, лучше подождать, пока в системе останется мало пользователей, выполняющих такое обслуживание.

5 голосов
/ 05 мая 2011

Ваша проблема выглядит так, как будто вы смешиваете операции DML и DDL.Посмотрите этот URL, который объясняет эту проблему:

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

4 голосов
/ 27 ноября 2014

Просто проверьте процесс, удерживающий сеанс, и убейте его.Его обратно в нормальное состояние.

Ниже 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»;

2 голосов
/ 23 мая 2017

Я имел эту ошибку, когда у меня было 2 сценария, которые я выполнял. У меня было:

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

Я запустил удаление таблицы, затем создание таблицы под учетной записью № 1. Я запустил обновление таблицы во время сеанса № 2. Не совершать изменения. Повторно запустил скрипт удаления / создания таблицы в качестве учетной записи # 1. Ошибка в команде drop table x.

Я решил это, запустив COMMIT; в сеансе SQL * Plus учетной записи # 2.

...