Использование таблицы блокировки БД Oracle

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

  1. Транзакция, которая обновляла таблицу, была распределенной, поэтому я не мог ее контролировать,
  2. В течение дня должны одновременно поддерживаться тысячи неблокирующих транзакций, назовем их «общими» операциями,
  3. Каждая «общая» операция обновляла строки в конкретной «ветви» («LDN», «NY», «LA» ...),
  4. Once a day there is a 'master' operation for each branch, which happen spanteniously, on different branches,
    1. During 'master' operation no 'general' operations on that branch can happen.
    2. При запуске «мастерской» операции она должна дождаться завершения текущей «общей» операции по предоставленной ветке, которая была в системе до прихода «мастерской» операции.
    3. Во время «основной» обработки в определенной ветке все остальные ветки могут быть обновлены.

Чтобы заархивировать это, я создал специальную таблицу Oracle DB.

create table BRANCH_LOCK(
    BRANCH VARCHAR2(10),
    FLAG   VARCHAR2(1),
    CONSTRAINT "PK_BRANCH_LOCK" PRIMARY KEY ("BRANCH")
)

Поддерживался следующий функционал для различных операций:

Для «общих» операций:

1. In the same XA transaction each operation locks BRANCH_LOCK table 
   in SHARE mode,
2. After locking it checks FLAG, on updated branch,
  1. If flag is 'Y', that means that currently 'master' 
      operation is in progess, so  Exception is thrown, 
     and no further processing is done;
  2. If flag is 'N' than everything is OK, and general processing is done;

Для «ведущей» операции:

  1. When 'master' operation comes I start separate transaction which:
    1. Lock BRANCH_LOCK table in EXCLUSIVE mode, which transaction can not acquire while there is SHARE mode LOCK on this table in a different transaction (This way, I guarantee that 'master' operation would start after all current 'general' operation finish, although it waits for transactions on all branches to finish, not only specified one),
    2. Устанавливает флаг для ветки на «Y» (таким образом я гарантирую, что не будет «общих» транзакций при обработке «основной» операции),
  2. Во входящей транзакции я меняю флаг в таблице на «N», поэтому после фиксации таблица BRANCH_LOG будет иметь соответствующее значение в столбце FLAG, и система сможет снова обрабатывать «общие» операции.

Это еще не запущено в производство, поэтому мне интересно, есть ли лучшее решение для этого, и есть ли еще недостатки, кроме описанного?

Некоторые обновления, о которых я не упомянул:

  1. «Главная» операция работает с результатами «общих» операций. Поэтому очень важно, чтобы ни одна «общая» операция не была потеряна во время «основной» обработки, поэтому текущая «общая» операция должна быть завершена до начала обработки основной операции. .
  2. Несколько «общих» операций в одной и той же ветке происходят каждую секунду, около 3000 операций в секунду,
  3. Для ветки может выполняться только одна «главная» операция, одновременно могут выполняться несколько «главных» операций в разных ветвях.

person mavarazy    schedule 02.02.2011    source источник
comment
Мне не понятна ваша точка зрения (1). Какое отношение имеет его распространение к тому, можете ли вы его контролировать? Кроме того, это относится к общей или основной операции?   -  person Dave Costa    schedule 02.02.2011
comment
Вы подразумеваете, но не заявляете прямо, что несколько общих операций в одной и той же ветке могут работать одновременно. Это правильно?   -  person Dave Costa    schedule 02.02.2011
comment
По поводу комментариев. Что касается пункта 1, то все общие и основные операции распределены, поэтому я не знаю, когда начинается транзакция, и когда она будет зафиксирована или откатана, я не контролирую эти моменты времени. Что касается общих операций, то в одной и той же ветке должно поддерживаться 3000 операций в секунду, поэтому да, для одной ветки одновременно может выполняться несколько операций.   -  person mavarazy    schedule 03.02.2011


Ответы (3)


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

person ik_zelf    schedule 02.02.2011
comment
Это бизнес-требование, никакие общие операции не должны обрабатываться во время «главной» операции, и не должно быть текущих «общих» операций при запуске «основной» операции, иначе мы получим несогласованность данных. Кроме того, операция «мастер» требует в 1000 раз больше времени, чем обычная. - person mavarazy; 02.02.2011
comment
Антон, все ли данные хранятся в базе данных оракула? или данные также управляются в файлах? Если управлять только базой данных оракула, проблем не должно быть из-за согласованного чтения. Если данные, которые должны согласовываться с базой данных, также находятся за пределами базы данных, я бы серьезно переосмыслил эту часть. - person ik_zelf; 02.02.2011
comment
Вся информация хранится в БД Oracle. Я не думаю, что согласованность здесь работает, потому что основная операция должна обрабатывать изменения, сделанные общими операциями в течение дня, и важно, чтобы ни одна «общая» операция не была потеряна. Таким образом, если есть незафиксированные изменения, сделанные текущими «общими» операциями, они не будут видны основной операцией и потеряны в основном процессе, что неприемлемо. Так что постоянство здесь не работает. - person mavarazy; 03.02.2011
comment
Я вижу, что отсутствие обновлений не приносит удовольствия. В связи с этим мой следующий вопрос: что происходит с транзакциями, которые регистрируются после завершения основного процесса и снятия блокировки? Я могу себе представить, что приложение каким-то образом распознает новые транзакции? Если это основано на времени, вы будете искать новые tx, созданные после даты начала последнего мастер-запуска. Если это так, вы можете использовать обычное последовательное чтение, если спросите меня. - person ik_zelf; 03.02.2011
comment
Я подумал, что если «общая» и «главная» транзакция будут изменять одну и ту же строку? Один установит, скажем, 5 в ЦИФРОВОЙ строке, другой установит 10. Каков будет результат и какое обновление будет потеряно? С точки зрения бизнеса угадывание неприемлемо. И система должна гарантировать, что ничего не потеряно. Таким образом, с моей точки зрения чтение согласованности не является вариантом. Также бизнес будет получать жалобы от своих клиентов на отложенные обновления, что также недопустимо. - person mavarazy; 04.02.2011

Вместо того, чтобы создавать свою собственную таблицу блокировки, я думаю, что я бы попытался использовать пакет блокировки Oracle DBMS_LOCK.

Это более эффективно, чем использование DML для блокировки, и это то, что Oracle использует внутри себя для выполнения блокировки постановки в очередь.

person DCookie    schedule 02.02.2011
comment
Хорошо, на самом деле я не администратор баз данных, я разработчик, поэтому я не знал об этой способности, я посмотрю на нее, спасибо. - person mavarazy; 03.02.2011
comment
Скорее всего, вашему администратору баз данных потребуется предоставить вам разрешение на выполнение этого пакета. - person DCookie; 04.02.2011

Какие объемы таблиц.

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

CREATE OR REPLACE PROCEDURE do_master (in_branch IN VARCHAR2) IS
BEGIN
  SELECT ...
  BULK COLLECT INTO
  FROM ...
  WHERE branch = in_branch
  FOR UPDATE OF branch;
  ...
END do_master;

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

Но если объемы большие, то SELECT...FOR UPDATE может быть очень большим. Именно тогда я бы рассмотрел решение DBMS_LOCK.

person Gary Myers    schedule 02.02.2011
comment
Да, объемы большие, это финансовый продукт, и данные дублируются почти каждый день с миллионами записей. Хотя у нас такая блокировка в БД, которая содержит часть ПК измененной записи, без даты. Однако есть проблема: если новая транзакция создаст новую запись в этой ветке, эта запись не будет видна предоставленным запросом. Так что это обновление будет потеряно. Также, с моей точки зрения, лучше установить флаг в одной записи в одной таблице, чем блокировать 1 000 000 записей в другой. - person mavarazy; 03.02.2011