Teradata: как вы отлаживаете транзакцию, прерванную из-за ошибок взаимоблокировки?

В последнее время мы сталкиваемся с ошибкой Transaction ABORTed due to Deadlock, когда идем обновлять запись в одной из наших таблиц. Что-то блокирует этот стол, и он не выпускается, но я потратил буквально рабочие дни, пытаясь его отследить, и он все еще ускользает от меня.

Хотя ошибка случайна, я знаю, какой повторяющийся цикл шагов мне нужно повторить, чтобы в конечном итоге вызвать ее. Однако я запросил dbc.DBQLogTbl и просмотрел все SQL-запросы, которые были выполнены за 2 минуты до и после возникновения ошибки, и, похоже, ничего не выбирается из любой таблицы без блокировки доступа. Кроме того, после возникновения ошибки я нажму F5 повторно отправлю веб-форму обратно на сервер, чтобы повторить тот же набор обновлений, и он будет работать.

Я догадываюсь, что какой-то процесс за пределами нашего приложения ASP.NET блокирует таблицу, поскольку я проверил весь SQL, выполняемый нашим приложением. Я думаю, что должен быть способ узнать, какой именно SQL был выполнен, который заблокировал таблицу.

8/9/2012 Дополнительная информация: В этом порядке в рамках одной транзакции происходит все следующее:

  • обновить таблицу сотрудников
  • блокирующая строка для доступа select * from employeeesecurity, где empid = X (сделайте это, чтобы получить текущую запись сотрудника, чтобы увидеть, не изменилось ли что-нибудь)
  • если есть изменения, обновите вышеупомянутую запись о безопасности сотрудников
  • обновить таблицу employeeconfig (здесь всегда возникает ошибка взаимоблокировки)

Я не упоминал об этом раньше, но ошибка взаимоблокировки возникает в таблице, из которой я вообще не выбираю. Когда страница загружается, я читаю из представления employeeconfig, но в представлении указано locking row for access.

Ответьте на 4 вопроса Роба:

  • Это всего лишь одна транзакция.
  • Как я сказал в своем последнем обновлении, заблокированная таблица - это даже не та таблица, из которой выбирается.
  • Во всех запросах используется locking row for access
  • Выбираем из вида employeeconfig. Это представление выбирает из таблицы employeeconfig с помощью locking row for access. Мы не используем locking row for access при запросе самого представления.

Что касается обработки тупика, я бы не хотел, чтобы код просто пытался повторно отправить его, поскольку это похоже на проблему, которую необходимо исправить. Как ты сказал, Роб, возможно, мой доступ к dbc.DBQLogTbl ограничен, поэтому, возможно, я просто не могу видеть все, что происходит. Я был в контакте с администратором баз данных и свяжусь с вами сегодня снова.


person oscilatingcretin    schedule 07.08.2012    source источник
comment
Я считаю, что если вы столкнетесь с ошибкой взаимоблокировки, ваше приложение попытается хотя бы один раз повторить прерванную транзакцию. Использует ли ваша среда Viewpoint? Если да, то можете ли вы использовать его с функцией «Перемотка назад» и портлетом «Монитор запросов»?   -  person Rob Paller    schedule 08.08.2012
comment
Да, мы используем точку зрения, но мне не удалось ее выяснить. Я пытаюсь использовать идентификатор сеанса, полученный при запросе dbc.DBQLogTbl, но ViewPoint, похоже, его не находит. Кроме того, вкладка SQL в мониторе запросов всегда неактивна. Есть ли какой-либо другой способ узнать, какой SQL блокирует таблицу или ViewPoint является практически единственным вариантом?   -  person oscilatingcretin    schedule 08.08.2012
comment
Viewpoint просто поможет идентифицировать другие сеансы, которые были активны на момент прерывания вашей транзакции. SQL может не отображаться в зависимости от разрешений портлета, установленных для вашей роли в Viewpoint. (См. Команду DBA.)   -  person Rob Paller    schedule 08.08.2012
comment
Какой уровень блокировки применяется к таблице EmployeeConfig для оператора обновления? Я предполагаю, что вы выполняете обновление одной строки и квалифицируетесь по первичному индексу.   -  person Rob Paller    schedule 09.08.2012
comment
Да, однострочное обновление первичного индекса. Я не указываю никаких блокировок для обновления. По сути, я просто использую update employeeconfig set field = x where id = y.   -  person oscilatingcretin    schedule 09.08.2012
comment
Подробнее об использовании блокировки ROW EXCLUSIVE для вашего оператора UPDATE см. В ответе. Попробуйте это и посмотрите, сможете ли вы воспроизвести / устранить тупик.   -  person Rob Paller    schedule 09.08.2012
comment
Я попробовал это с помощью ОБНОВЛЕНИЯ и получил [Teradata Database] [3778] SELECT statement must follow LOCK ROW modifier.   -  person oscilatingcretin    schedule 09.08.2012


Ответы (2)


Определение прерванных транзакций

Условие взаимоблокировки должно приводить к прерыванию обеих транзакций, ответственных за взаимоблокировку. Обычно я вижу тупиковые ситуации с оптимизацией push down от Informatica, пытающейся создать временные представления параллельно, и тупиковые ситуации в таблицах DBC, необходимых для создания представлений. Как и ваша ситуация, наша ситуация с Informatica совершенно случайна. Мы можем обходиться неделями или месяцами без прерывания из-за тупика.

Вы можете найти подозрительные транзакции, запросив в таблице журнала DBQL транзакции с ErrorCode = 2631 (Edit: Fixed error code) и ORDER BY StartTime DESC. Это даст вам каждую транзакцию, которая была прервана из-за тупиковой ситуации. Пары транзакций, которые привели к тупиковой ситуации, должны быть довольно близко друг к другу, если не объединены в пары по сортировке.

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

Определение причин прерывания транзакций

Примечание. Это не исчерпывающий список.

Хуже всего в таких условиях тупика, что они обычно возникают случайно. Закон Мерфи гласит, что эти случайные события будут иметь место, когда вы спите, в отпуске или в другом случае, когда вы не хотите, чтобы вас беспокоили. В зависимости от вашей конкретной ситуации вы можете просто повторно отправить транзакции, которые оказались в тупике.

Это потребует от вас сначала понять, как вы попадаете в состояние тупика.

  • Если две транзакции пытаются манипулировать одной и той же записью, поддерживает ли ваша модель данных медленно меняющиеся измерения, чтобы у вас была запись о каждом происходящем изменении?
  • Если это транзакция чтения и транзакция обновления, обращающаяся к одной и той же записи, можете ли вы настроить степень детализации и продолжительность блокировки, чтобы минимизировать шансы?
  • Вы используете ACCESS или READ блокировку?
  • Обращаются ли ваши SELECT операторы к таблице через представление 1: 1, в котором используется ROWHASH ACCESS блокировка, позволяя оптимизатору наращивать блокировку с наиболее детализированного уровня до уровня, необходимого для рассматриваемой транзакции? (например, LOCKING ROW FOR ACCESS SELECT * FROM DBC.DBCInfo;)
  • Удалено предложение для БЛОКИРОВКИ СТРОК в ЗАЯВЛЕНИИ ОБ ОБНОВЛЕНИИ.

Обработка прерванных транзакций

В зависимости от обстоятельств, связанных с вашим условием взаимоблокировки, вы можете выбрать, чтобы ваш процесс пытался повторно отправить неудавшуюся транзакцию заранее определенное количество раз. У вас может возникнуть ситуация, когда один процесс может быть отправлен повторно, а другой, возможно, придется остаться в состоянии сбоя, чтобы кто-то другой мог проверить его перед продолжением. Первое может быть вашим веб-приложением, а второе - сложным потоком ETL, который нельзя перезапустить вслепую.

Вы должны где-нибудь зарегистрировать, что это произошло, или иметь какой-либо другой механизм отчетности для отслеживания этих инцидентов.

person Rob Paller    schedule 08.08.2012
comment
Итак, я попытался запросить этот код ошибки (который на самом деле 2631), и единственный SQL, который обнаружился, находится в транзакции, которую я открыл. Однако я думаю, что понял, как вызвать ошибку, но не почему это происходит. Смотрите обновление моего ответа. - person oscilatingcretin; 08.08.2012
comment
Я обновил свой вопрос. Я ценю время, которое вы так долго потратили, но если вы больше ничего не можете сделать, я пойму. Мне нужно решить эту проблему к этим выходным, так как мы развертываем этот выпуск, поэтому я обязательно обновлю этот вопрос тем, что узнаю. - person oscilatingcretin; 09.08.2012

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

Почему в этих случаях сервер базы данных не пытается повторить транзакцию самостоятельно? Поскольку клиент может использовать данные, возвращенные из одного запроса в транзакции, чтобы влиять на то, какие виды обновлений выполнять в последующих обновлениях в рамках той же транзакции. Таким образом, ответственность за повторение транзакций лежит на клиенте в редких (но вполне нормальных и ожидаемых) случаях, когда транзакции прерываются.

Итак, ответ таков: прерванные транзакции - это совершенно нормально, и вы просто должны повторить их со стороны клиента. Но, как заметил Роб, это может быть легко или сложно, в зависимости от типа транзакции, которую вы выполняете (например, если вы выполняете 2-часовой процесс ETL, вы можете вместо этого выяснить, как уменьшить вероятность взаимоблокировок) .

person Eirik Bakke    schedule 06.10.2013