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

115

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

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

  • 20
    Обычно это помогает, если вы публикуете утверждение, которое приводит к ошибке
Теги:
ora-00054

14 ответов

128
Лучший ответ

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

  • 44
    Я бы добавил к этому «в другой сессии». Одним из распространенных сценариев является то, что вы протестировали обновление в инструменте, скажем, SQL Developer или Toad, а затем попытались запустить его где-нибудь еще, пока первая сессия все еще удерживает блокировку. Поэтому вам нужно зафиксировать / откатить другой сеанс, прежде чем вы сможете снова запустить обновление.
  • 1
    Скорее всего DML (вставка / удаление / обновление), а не запрос. И в другой сессии. Просто потому, что парень, который спросил, кажется новичком, ответ может быть правильным. Но вы НЕ МОЖЕТЕ совершать обязательства от имени других пользователей в производственной системе.
Показать ещё 2 комментария
70

отсюда ORA-00054: ресурс занят и приобретается с указанным NOWAIT

Вы также можете найти информацию о sql, username, machine, port и перейти к фактическому процессу, который содержит соединение

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;
  • 4
    Мне пришлось удалить s.port из запроса, но это позволило мне найти виновника
  • 0
    замки временные. так что, если вставка приходит, то вы немедленно фиксируете. это не будет отображаться в этом запросе. вы все равно можете получить ошибку, если вы введете «DDL». пока транзакция открыта. см. мой пост ниже. Это действительно легко обойти.
Показать ещё 3 комментария
31

Убейте сеанс 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;

убить как

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

  • 1
    Следует предостеречь этот ответ от того, какие привилегии требуются. У меня есть CONNECT и RESOURCE , но не все, что мне нужно, с моей учетной записью, и он говорит ORA-00942: table or view does not exist . Не каждый, кто читает эту ветку, будет иметь учетную запись SYS .
  • 0
    Если вы также добавите столбец выбора «S.OSUSER», вы будете знать, какой пользователь выполнял эту транзакцию, и это будет удобно, если вы захотите проверить пользователя перед тем, как завершить сеанс.
Показать ещё 2 комментария
13

Для этой проблемы очень легко работать.

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

LOCK TABLE 'TABLE_NAME' NO WAIT

Итак, если другой сеанс имеет открытую транзакцию, вы получаете сообщение об ошибке. Так что исправить... барабан рулон пожалуйста. Выпустите свой собственный замок перед DDL и оставьте "NO WAIT".

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

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

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

  • LOCK TABLE 'TABLE NAME'; - вы будете "ждать" (разработчики называют это повешение). до завершения сеанса с открытой транзакцией. Это очередь. поэтому впереди вас может пройти несколько сеансов. но вы НЕ будете ошибаться.
  • Выполнить DDL. Затем ваш DDL запустит блокировку с NO WAIT. Однако ваша сессия приобрела замок. Итак, вы хорошо.
  • Автокоманды DDL. Это освобождает блокировки.

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

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

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

  • 3
    хорошо это неправильно в 11g используйте set_ddl_timeout, это доступно только в 11g. oracle делает коммит перед выполнением DDL, поэтому снимает блокировку. В 11g вы можете ждать DDL. Я делаю это сейчас. Работает отлично.
  • 3
    в 11g вы должны использовать LOCK TABLE table_name В ЭКСКЛЮЗИВНОМ РЕЖИМЕ;
Показать ещё 3 комментария
6

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

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

Найти SID,

SELECT * FROM V$OPEN_CURSOR WHERE SID = --the id
  • 0
    Не каждый будет иметь доступ к этим взглядам. Я получаю ORA-00942: table or view does not exist .
  • 0
    В таких случаях администраторы БД несут ответственность за предоставление этой информации.
Показать ещё 1 комментарий
5

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

Если у вас есть доступ к системе администрирования 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);

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

  • 0
    И как вы узнаете сеанс для уничтожения для alter system kill session '.... сеанса уничтожения alter system kill session '.... если у вас нет доступа к представлениям управления?
  • 0
    Это я не знаю.
4

Ваша проблема заключается в том, что вы смешиваете операции DML и DDL. См. Этот URL, который объясняет эту проблему:

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

2

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

  • Я нашел оскорбительную сессию с:

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

    Сеанс был неактивным, но он все равно удерживал блокировку. Обратите внимание, что вам может потребоваться использовать другое условие WHERE в вашем случае (например, try USERNAME или MACHINE).

  • Убит сеанс с помощью полученных ID и SERIAL# сеансов:

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

  • 0
    Если ни один из предыдущих запросов open-session не работает, попробуйте этот.
1

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

Ниже 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#'

ИЛИ

Некоторый пример, который я нашел в Интернете, также нуждается в идентификаторе экземпляра alter system kill session '130,620, @1';

0

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

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

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

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

  • 0
    Если у вас нет прав на удаление таблицы, что вы будете делать? Плохой ответ
  • 1
    Shakeer, это был всего лишь пример того, что я делал, когда это случилось со мной, а не решение проблемы - это было в моей последней строке - запуск COMMIT; , Если вы даже не можете удалить таблицу, у вас нет прав, чтобы изменить что-либо, что в первую очередь привело бы вас к этой проблеме.
0

Мне удалось ударить эту ошибку, просто создав таблицу! Там не было никаких проблем, очевидно, раздор на столе, который еще не существует. Оператор CREATE TABLE содержал предложение CONSTRAINT fk_name FOREIGN KEY, ссылающееся на хорошо заполненную таблицу. Мне пришлось:

  • Удалить предложение FOREIGN KEY из инструкции CREATE TABLE
  • Создайте INDEX в столбце FK
  • Создайте FK
  • 0
    У меня просто была такая же проблема. Мне удалось создать таблицу после удаления определения fk из оператора ddl, но я не могу добавить ее даже после того, как создал индекс для столбца.
  • 0
    Я смог решить это. Сначала я добавил предложение novalidate в alter table add constraint . Это как-то позволяет ему работать, но оно блокируется. Затем я посмотрел на блокировки сеанса, чтобы выяснить, на каком сеансе он блокируется. А потом я убил эту сессию.
-1

Удаление моего сообщения, поскольку оно не полезно в контексте вопроса. ORA-00054 происходит главным образом при выполнении DDL (ALTER, TRUNCATE и т.д.).

см. это

SELECT FOR UPDATE является единственным исключением как DML, я думаю.

-2

Я также сталкиваюсь с аналогичной проблемой. Для устранения этой ошибки ничего не требуется программисту. Я сообщил моей команде DBA оракула. Они убивают сеанс и работают как шарм.

  • 1
    Кто-то еще должен что-то сделать. Что, если команда DBA не знает, что делать и как убить сеанс? Плохой ответ
  • 0
    Если администратор базы данных не знает, как убить сессию, он не может работать
Показать ещё 1 комментарий
-4

Решение, данное ссылкой Shashi, является лучшим... не нужно связываться с dba или кем-то еще

сделать резервную копию

create table xxxx_backup as select * from xxxx;

удалить все строки

delete from xxxx;
commit;

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

insert into xxxx (select * from xxxx_backup);
commit;
  • 10
    удалить / усечь не являются взаимозаменяемыми. выполнение большого количества удалений имеет огромное значение для производительности. Это действительно плохо.
  • 0
    Я думал, что это общая картина.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню