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

Откуда:
Сообщений: 7076
Если таблица вида id PK, field1, field2, ..., fieldN. id заполняется посредством ON INSERT триггера в sequence.NEXTVAL.
Есть набор значений field1, field2, ..., fieldN. Если их еще нет в таблице, надо вставить их и вернуть сгенерированный id, иначе - вернуть id записи с такими field1, field2, fieldN.
Эту операцию могут одновременно производить две и более сессии с одинаковым набором значений field1, field2, ..., fieldN.

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

По field1, field2, ..., fieldN нет UK. Одно из полей высокоселективно (практически уникально), но теоретически возможны повторы, поэтому UK по нему (и соответствующие игры с хинтами для INSERTа) недопустимы.

Как минимум рассмотреть вариант, когда транзакция каждой сессии состоит только из вставки/пропуска вставки и получения идентификатора записи. Как максимум (впрочем, думаю это невозможно) рассмотреть вариант, когда в транзакции каждой сессии много операций и полученный идентификатор потом используется дальше, НО в случае отката транзакции, которая вставила запись в случае её отсутствия, если эту запись уже успела использовать другая транзакция, вставленную запись не откатывать (понимаю, что это противоречит принципу всё или ничего).
3 фев 11, 02:45    [10174699]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
an0nym
Member

Откуда:
Сообщений: 7076
an0nym
Если таблица вида ...

Есть таблица вида ...
3 фев 11, 02:46    [10174700]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
an0nym
Member

Откуда:
Сообщений: 7076
an0nym
Если их еще нет в таблице, надо вставить их и вернуть сгенерированный id, иначе - вернуть id записи с такими field1, field2, fieldN.

field1, field2, ..., fieldN.
3 фев 11, 02:53    [10174705]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
-2-
Member

Откуда:
Сообщений: 15330
an0nym
По field1, field2, ..., fieldN нет UK.
Так сделай
3 фев 11, 08:23    [10174901]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
Elic
Member

Откуда:
Сообщений: 29976
Ручная сериализация посредством
dbms_lock.request(..., release_on_commit=true);
3 фев 11, 08:38    [10174939]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
an0nym
Member

Откуда:
Сообщений: 7076
-2-
an0nym
По field1, field2, ..., fieldN нет UK.
Так сделай

Он будет по размеру больше таблицы и не эффективен.
3 фев 11, 11:42    [10176324]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
an0nym
Member

Откуда:
Сообщений: 7076
Elic
Ручная сериализация посредством
dbms_lock.request(..., release_on_commit=true);

Спасибо, почитаю.
3 фев 11, 11:42    [10176329]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
Кроик Семён
Member

Откуда: СПб --> Dortmund
Сообщений: 6655
-2-
an0nym
По field1, field2, ..., fieldN нет UK.
Так сделай


+1
3 фев 11, 11:46    [10176373]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
_Nikotin
Member

Откуда: СПб
Сообщений: 2965
an0nym
НО в случае отката транзакции, которая вставила запись в случае её отсутствия, если эту запись уже успела использовать другая транзакция, вставленную запись не откатывать (понимаю, что это противоречит принципу всё или ничего).

А как это другая транзакция сможет использовать строку до коммита?
3 фев 11, 11:51    [10176425]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
Сергей Арсеньев
Member

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

Для обхода мутации, вставлять во вьюшку, а через ее триггер в автономке построчный комит с запоминанием сессии в списке транзакций писавших данный id.
Перед комитом основной транзакции помечать в журнала id-шники, которые правились данной транзакцией как закомиченный основной транзакцией (ввести в таблице поле соответвующее).
Периодически удалять строчки c id все транзакции которых завершились и ни разу не закомитились.
3 фев 11, 12:06    [10176565]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 51751

an0nym
Он будет по размеру больше таблицы и не эффективен.

Интересно, как это уникальный индекс может быть неэффективным?..

Posted via ActualForum NNTP Server 1.4

3 фев 11, 12:21    [10176686]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
an0nym
Member

Откуда:
Сообщений: 7076
Dimitry Sibiryakov,

сравните эффективность уникального индекса по field1, field2, field3, ..., fieldN и неуникального индекса по высокоселективному полю field1, а лучше неуникального функционального индекса ORA_HASH(field1).

id NUMBER, field1 VARCHAR2(1024), field2 VARCHAR2(1024), field3 VARCHAR2(1024), ..., fieldN VARCHAR2(1024).
3 фев 11, 12:42    [10176865]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
an0nym
Member

Откуда:
Сообщений: 7076
_Nikotin
А как это другая транзакция сможет использовать строку до коммита?

Вот меня это тоже смущает. Тут мало того, что будет грязное чтение (вроде это так называется?), так еще если это грязное чтение случилось - транзакция, вставившая эту грязно прочитанную запись, должна откатиться не полностью. Поэтому сразу и написал, что скорее всего это невозможно (но вдруг).
3 фев 11, 12:44    [10176883]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
an0nym
Member

Откуда:
Сообщений: 7076
Предположим, будет UK.

Насколько хорошая практика использовать хинт IGNORE_ROW_ON_DUPKEY_INDEX? Я пришел из MySQL и там есть штатное рекомендуемое средство INSERT IGNORE INTO table VALUES(...), аналогичное по действию данному хинту. С какими проблемами могу столкнуться при использовании данного хинта?
4 фев 11, 10:44    [10182201]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
-2-
Member

Откуда:
Сообщений: 15330
an0nym
Предположим, будет UK
exception when dup_val_on_index. Однако "VARCHAR2(1024), VARCHAR2(1024), ..." - индекс не может содержать ключ длиннее ~80% блока (40% в зависимости от версии).
4 фев 11, 10:55    [10182329]     Ответить | Цитировать Сообщить модератору
 Re: Вставить запись в таблицу, если её в ней еще нет, и вернуть её идентификатор  [new]
an0nym
Member

Откуда:
Сообщений: 7076
-2-,

насчёт ограничений упомянутых вами знаю, буду проверять, поместится ли.

А как exception when dup_val_on_index в сравнении с хинтом? Что портабельнее, стабильнее, менее багнутое?
4 фев 11, 11:06    [10182460]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить