Поздно поздно я столкнулся с множеством споров о блокировке строк. Стол в споре, кажется, является конкретной таблицей.
Это вообще то, что происходит -
- Разработчик 1 запускает транзакцию с экрана интерфейса Oracle Forms
- Разработчик 2 запускает другую транзакцию из другого сеанса, используя тот же экран
~ 5 минут через, передний конец кажется не отвечает. Проверка сеансов показывает конфликт блокировки строк. «Решение», которое каждый выбрасывает, - убивать сессии: /
Как разработчик базы данных
- Что можно сделать, чтобы устранить проблемы блокировки строк?
- Можно ли выяснить, какая строка хранимой процедуры вызывает эти споры о блокировке строки
- Каково будет общее руководство для уменьшения / предотвращения / устранения таких проблем, которые связаны с кодированием?
Если этот вопрос кажется слишком открытым / недостаточно информации, пожалуйста, не стесняйтесь редактировать / дайте мне знать - я сделаю все возможное, чтобы добавить дополнительную информацию.
В этой таблице много вставок и обновлений, я бы сказал, что это одна из самых загруженных таблиц. SP довольно сложен - чтобы упростить - он выбирает данные из различных таблиц, заполняет их в рабочие таблицы, на рабочей таблице происходит много арифметических операций, и результат рабочей таблицы вставляется / обновляется в рассматриваемой таблице.
Версия базы данных - Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64-разрядная версия. Поток логики выполняется в одном и том же порядке в обеих сессиях, транзакция не остается открытой слишком долго (или, по крайней мере, мне так кажется ), и блокировки происходят во время активного выполнения транзакций.
Обновление: количество строк в таблице больше, чем я ожидал, около 3,1 миллиона строк. Кроме того, после отслеживания сеанса я обнаружил, что пара операторов обновления для этой таблицы не использует индекс. Почему это так - я не уверен. Столбец, указанный в предложении where, индексируется. В настоящее время я перестраиваю индекс.
источник
COMMIT
илиROLLBACK
в разумные сроки, либо б) устроить так, чтобы одни и те же люди не всегда хотели один и тот же ряд в одно и то же время.Ответы:
Не совсем, но вы можете получить оператор SQL, вызывающий блокировку, и, в свою очередь, определить связанные строки в процедуре.
В разделе «Руководство по концепциям Oracle» о блокировках говорится: «Строка блокируется только при изменении ее автором». Другой сеанс, обновляющий эту же строку, будет ожидать первого сеанса до
COMMIT
илиROLLBACK
до его продолжения. Чтобы устранить проблему, вы можете сериализовать пользователей, но вот некоторые вещи, которые могут уменьшить проблему, возможно, до уровня, когда она не будет проблемой.COMMIT
почаще. КаждыйCOMMIT
выпуск блокируется, поэтому, если вы можете делать обновления в пакетах, вероятность того, что другой сеанс будет нуждаться в той же строке, уменьшается.UPDATE t1 SET f1=DECODE(f2,’a’,f1+1,f1);
должен быть переписан как более избирательный (читайте меньше блокировок)UPDATE t1 SET f1=f1+1 WHERE f2=’a’;
. Конечно, если изменение оператора по-прежнему блокирует большинство строк в таблице, то изменение принесет пользу только для удобства чтения.BULK COLLECT ... FORALL
.UPDATE
иCOMMIT
. Например, если код отправляет сообщение электронной почты после каждого обновления, рассмотрите возможность размещения сообщений в очереди и отправки их после фиксации обновлений.SELECT ... FOR UPDATE NOWAIT
илиWAIT 2
. Затем вы можете поймать невозможность заблокировать строку и сообщить пользователю, что другой сеанс изменяет те же данные.источник
Я предоставлю ответ с точки зрения разработчика.
По моему мнению, когда вы сталкиваетесь с конфликтом строк, таким как описанный вами, это происходит из-за ошибки в вашем приложении. В большинстве случаев этот тип разногласий является признаком уязвимости с потерянным обновлением. Эта ветка на AskTom объясняет концепцию потерянного обновления:
Вы испытали один неприятный побочный эффект потерянного обновления: сеанс 2 может быть заблокирован, так как сеанс 1 еще не зафиксирован. Однако главная проблема заключается в том, что сессия 2 слепо обновляет запись. Предположим, что обе сессии выдают утверждение:
После обоих утверждений изменения сеанса 1 были перезаписаны, причем сеанс 2 не был уведомлен о том, что строка была изменена сеансом 1.
Потерянное обновление (и побочный эффект конкуренции) никогда не должно произойти, их можно избежать на 100%. Вы должны использовать блокировку, чтобы предотвратить их двумя основными методами: оптимистическая и пессимистическая блокировка .
1) Пессимистичная блокировка
Вы хотите обновить строку. В этом режиме вы запретите другим изменять эту строку, запрашивая блокировку этой строки (
SELECT ... FOR UPDATE NOWAIT
оператор). Если строка уже изменяется, вы получите сообщение об ошибке, которое вы можете изящно перевести конечному пользователю (эта строка изменяется другим пользователем). Если строка доступна, внесите изменения (ОБНОВЛЕНИЕ), а затем подтвердите, когда ваша транзакция будет завершена.2) Оптимистическая блокировка
Вы хотите обновить строку. Однако вы не хотите поддерживать блокировку этой строки, возможно, потому что вы используете несколько транзакций для обновления строки (веб-приложение без сохранения состояния), или, возможно, вы не хотите, чтобы какой-либо пользователь удерживал блокировку слишком долго ( что может привести к блокировке других людей). В этом случае вы не будете запрашивать блокировку сразу. Вы будете использовать маркер, чтобы убедиться, что строка не изменилась, когда будет выпущено ваше обновление. Вы можете кэшировать значение всех столбцов или использовать столбец отметки времени, который обновляется автоматически, или столбец на основе последовательности. Независимо от вашего выбора, когда вы собираетесь выполнить обновление, вы убедитесь, что маркер в этой строке не изменился, выполнив такой запрос:
Если запрос возвращает строку, сделайте обновление. Если это не так, это означает, что кто-то изменил строку с момента последнего запроса. Вам придется перезапустить процесс с самого начала.
Примечание. Если вы полностью доверяете всем приложениям, обращающимся к вашей БД, вы можете рассчитывать на прямое обновление для оптимистической блокировки. Вы можете оформить напрямую:
Если инструкция не обновляет строку, вы знаете, что кто-то изменил эту строку, и вам нужно начинать все сначала.
Если все приложения согласны с этой схемой, вы никогда не будете заблокированы кем-то другим, и вы избежите слепого обновления. Однако, если вы не заблокируете строку заранее, вы все еще подвержены неопределенной блокировке, если другое приложение, пакетное задание или прямое обновление не реализуют оптимистическую блокировку. Вот почему я советую всегда блокировать строку, независимо от того, какую схему блокировки вы выберете (снижение производительности может быть незначительным, поскольку вы получаете все значения, включая rowid, когда блокируете строку).
TL; DR
источник
Этот ответ, вероятно, будет претендовать на участие в The Daily WTF.
Хорошо, после отслеживания сессий и поиска
USER_SOURCE
- я выследил причинуисточник