Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Паралеллльный инсерт  [new]
Migelle
Member

Откуда:
Сообщений: 160
Доброго дня уважаемые!

Вот такая ситуация

есть примерная такая табличка

create table tbl(ID NUMBER, str VARCHAR2(100);


id - Primary key
есть уникальный индекс по str

Есть процесс работающий по такому принципу
BEGIN
    BEGIN
        SELECT id
          INTO v
          FROM tbl
         WHERE str = some_value;
    EXCEPTION
        WHEN ndf THEN
            v   := NULL;
    END;
    IF v IS NULL THEN
        INSERT INTO tbl (str)
             VALUES (some_value)
          RETURNING id
               INTO v;
    END IF;
END;

Когда начало работать несколько параллельных процессов появились ошибки дубликатов при инсерте, т.к. между чтением и инсертом другой процесс успевал вставить запись.
Переделал код так
BEGIN
    BEGIN
        SELECT id
          INTO v
          FROM tbl
         WHERE str = some_value;
    EXCEPTION
        WHEN ndf THEN
            v   := NULL;
    END;
    IF v IS NULL THEN
        BEGIN
            INSERT INTO tbl (str)
                 VALUES (some_value)
              RETURNING id
                   INTO v;
        EXCEPTION
            WHEN DUP_VAL_ON_INDEX THEN
                SELECT id
                  INTO v
                  FROM tbl
                 WHERE str = some_value;
        END;
    END IF;
END;

Но все равно выглядит некрасиво. Если соседний процесс, вставивший запись, откатит транзакцию получим исключение NO_DATA_FOUND.

А есть ли более красивые стандартные решения такой проблемы?
8 ноя 17, 10:16    [20935441]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Elic
Member

Откуда: 1984. Выбраковка финно-угром началась. КЯЗ
Сообщений: 27415
Самонаполняющийся справочник следует наполнять в автономке.
8 ноя 17, 10:23    [20935473]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Migelle
Member

Откуда:
Сообщений: 160
Elic,

Ну, это не справочник и его в автономку нельзя никак.
8 ноя 17, 10:31    [20935499]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Elic
Member

Откуда: 1984. Выбраковка финно-угром началась. КЯЗ
Сообщений: 27415
Migelle
нельзя никак.
Тебе, конечно же, виднее.
8 ноя 17, 10:34    [20935518]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
env
Member

Откуда: Россия, Москва
Сообщений: 5533
Migelle
Если соседний процесс, вставивший запись, откатит транзакцию
, то зададимся вопросом, что же тебе вернул тогда запрос в обработчике DUP_VAL_ON_INDEX ?
8 ноя 17, 10:37    [20935527]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Migelle
Member

Откуда:
Сообщений: 160
Elic,

В данном случае я упростил пример до того, что он стал выглядеть как справочник, но на самом деле это не так.

env,

ID генерится в триггере из сиквенса. После отката это будет несуществующий id
8 ноя 17, 10:54    [20935609]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Stax
Member

Откуда: Ukraine,Lviv
Сообщений: 552
Migelle
Если соседний процесс, вставивший запись, откатит транзакцию получим исключение NO_DATA_FOUND.

вот ето непонятно

......
stax
8 ноя 17, 10:55    [20935611]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Elic
Member

Откуда: 1984. Выбраковка финно-угром началась. КЯЗ
Сообщений: 27415
Migelle
В данном случае я упростил пример до того, что он стал выглядеть как справочник, но на самом деле это не так.
Migelle
автономку нельзя никак.
Это называется сериализация в конкуренции за ресурс.
8 ноя 17, 10:59    [20935623]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
982183
Member

Откуда:
Сообщений: 1150
Что-то подобное решали путем предварительного заполнения базы пустыми значениями, с генерацией необходимых ID.
Так что текущая работа делалась не инсертом а апдейтом.
8 ноя 17, 11:24    [20935712]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Migelle
Member

Откуда:
Сообщений: 160
Stax
Migelle
Если соседний процесс, вставивший запись, откатит транзакцию получим исключение NO_DATA_FOUND.

вот ето непонятно
stax


	Процесс 1		Процесс 2	
Время Результат Результат
-----------------------------------------------
t1 Select NO_DATA_FOUND
t2 Select NO_DATA_FOUND
t3 Insert Ok
t4 insert DUP_VAL_ON_INDEX
t5 Rollback
t6 Select NO_DATA_FOUND

Процесс 2 получает NO_DATA_FOUND

Elic
Это называется сериализация в конкуренции за ресурс.


Хорошо. А есть какие нибудь другие варианты решения?
8 ноя 17, 11:38    [20935752]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Elic
Member

Откуда: 1984. Выбраковка финно-угром началась. КЯЗ
Сообщений: 27415
Migelle
другие варианты решения?
Приведённый упрощённый пример тебе уже решили.
RTFM
8 ноя 17, 11:47    [20935778]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Stax
Member

Откуда: Ukraine,Lviv
Сообщений: 552
Migelle,

t4 ждет
DUP_VAL_ON_INDEX не будет
соответственно не будет t6

.....
stax
8 ноя 17, 11:52    [20935795]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Migelle
Member

Откуда:
Сообщений: 160
Stax
t4 ждет
DUP_VAL_ON_INDEX не будет
соответственно не будет t6
stax

Хм... Точно!
8 ноя 17, 12:06    [20935858]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Migelle
Member

Откуда:
Сообщений: 160
Elic
Приведённый упрощённый пример тебе уже решили

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

Неужели если бы я добавил в пример десяток-другой полей как-то повлияло бы на логику работы?
8 ноя 17, 12:20    [20935924]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Elic
Member

Откуда: 1984. Выбраковка финно-угром началась. КЯЗ
Сообщений: 27415
Migelle
Это заголовок журнала, который не имеет права существовать без подчиненных записей.
Ну и зачем параллельно создавать один и тот-же "заголовок"? Чтобы всем стоять в очереди?
RTFM
8 ноя 17, 12:23    [20935942]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Migelle
Member

Откуда:
Сообщений: 160
Elic
Ну и зачем параллельно создавать один и тот-же "заголовок"? Чтобы всем стоять в очереди?
Потому что к заголовку параллельно добавляются подчиненные записи множеством процессов. Первый процесс создает заголовок, остальные пользуются им.

Это не справочник и автономная транзакция не подходит.
8 ноя 17, 14:23    [20936518]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
де Феррабля
Guest
Если мастер-запись добавлять после дочерних, в конце основных манипуляций, то время конкуренции за мастера сократится и можно повысить troughput. Вставку мастера, если нет делитов, можно сделать как insert-select-where-not-exists и игнорировать dup_val_on_index.
8 ноя 17, 14:53    [20936664]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Stax
Member

Откуда: Ukraine,Lviv
Сообщений: 552
де Феррабля
Если мастер-запись добавлять после дочерних, в конце основных манипуляций, то время конкуренции за мастера сократится и можно повысить troughput. Вставку мастера, если нет делитов, можно сделать как insert-select-where-not-exists и игнорировать dup_val_on_index.

1) шоб делать детей надо знать ид отца
2) insert-select-where-not-exists не поможет, будут дубли да и загадочный RETURNING id под вопросом

.....
stax
8 ноя 17, 15:18    [20936760]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
XMLer
Member

Откуда:
Сообщений: 138
Migelle
Это заголовок журнала, который не имеет права существовать без подчиненных записей.

Ну так вставь фиктивную дочку а после, отдельным процессом, удали, если нужно.
Где вы такое находите....
9 ноя 17, 14:22    [20940145]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16198
Stax
де Феррабля
Если мастер-запись добавлять после дочерних, в конце основных манипуляций, то время конкуренции за мастера сократится и можно повысить troughput. Вставку мастера, если нет делитов, можно сделать как insert-select-where-not-exists и игнорировать dup_val_on_index.

1) шоб делать детей надо знать ид отца

Шоб делать детей - отца знать не надо, надо знать на кого записать приплод :)
А это вопрос техники генерации идентификаторов и не более того.
9 ноя 17, 14:29    [20940186]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Stax
Member

Откуда: Ukraine,Lviv
Сообщений: 552
andrey_anonymous
Шоб делать детей - отца знать не надо, надо знать на кого записать приплод :)
А это вопрос техники генерации идентификаторов и не более того.


сдесь и обсуждается техника генерации идентификаторов и не более того

.....
stax
9 ноя 17, 16:07    [20940636]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16198
Stax
сдесь и обсуждается техника генерации идентификаторов и не более того

Тогда непонятно в чем проблема сгенерироать ID, накидать чилдов а затем финальным аккордом обозначить парента.
Если сомнения касаются FK, то обратите внимание на ник того, кто это предложил - должно стать яснее :)
9 ноя 17, 16:42    [20940742]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
d.nemolchev
Member

Откуда: Кустанай
Сообщений: 301
Migelle,
Если ID в таблице не отрицательны, то можно так решить:
Begin
  Insert Into Tbl
    (Id, Str)
  Values
    (-trunc(Dbms_Random.Value(1, 1e9)), Some_Value)
  Returning Id Into v;
  Update Tbl t Set t.Id = Seq.Nextval Where t.Id = v Returning t.Id Into v;
Exception
  When Dup_Val_On_Index Then
    Null;
End;
/


Ваш триггер, генерирующий ID, должен поддерживать возможность пользовательской вставки ID:
Create Or Replace Trigger Tbl_Bir_Trg
  Before Insert On Tbl
  For Each Row
  When (New.Id Is Null) /*важно!*/
Begin
  :New.Id := Seq.Nextval;
End;

или на худой случай вот так:
Create Or Replace Trigger Tbl_Bir_Trg
  Before Insert On Tbl
  For Each Row
Begin
  If :New.Id Is Null Then /*важно!*/
    :New.Id := Seq.Nextval;
  End If;


Хотя я, лично я, строго против таких триггеров и настоятельно рекомендую использовать явную генерацию ID в коде приложения. Триггеров при реализации штатного функционала вообще желательно по возможности избегать.
9 ноя 17, 17:33    [20940937]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
d.nemolchev
Member

Откуда: Кустанай
Сообщений: 301
Небольшие пояснения к предыдущему сообщению:
Insert пытается вставить значение в уникальный индекс.
При этом ID генерируется случайное, вне диапазона рабочих значений.
Диапазон генерируемых значений ID выбран в 1 млрд для уменьшения вероятности блокировок сеансов разных пользователей, одновременно пробующих выполнить вставку значений (разных) в уникальный индекс.
Если вставляемое значение уже есть в таблице, то улетаем в exception DUP_VAL_ON_INDEX.
В противном случае никто более в другой сессии не сможет вставить такое же значение, какое вставили мы - они будут ждать завершения нашей транзакции в силу наличия уникального индекса на таблице.
В случае успешной вставки строки заменяем случайный ID на штатный из последовательности и на этом всё.
9 ноя 17, 17:43    [20940972]     Ответить | Цитировать Сообщить модератору
 Re: Паралеллльный инсерт  [new]
Stax
Member

Откуда: Ukraine,Lviv
Сообщений: 552
d.nemolchev,

у Migelle ситуация не с ID, а с str
20935441

....
stax
9 ноя 17, 17:50    [20940989]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Oracle Ответить