Проверка уникального индекса / ограничения оператора MERGE для каждой строки или для каждого оператора?

Предположим, у меня есть следующая таблица со следующими ограничениями:

create table test as (
    select 1 as id, 'a' as name from dual 
    union all 
    select 2, 'b' from dual 
    union all 
    select 3, 'c' from dual
);

create unique index ind on test(name);

alter table test add constraint constr unique (name);

select * from test;

        ID NAME
---------- ----
         1 a   
         2 b   
         3 c   

Предположим теперь, что я делаю следующее MERGE:

merge into test t using (
    select 4 as id, 'b' as name from dual 
    union all 
    select 2 as id, null as name from dual 
) s on (s.id = t.id) 
    when matched then update set t.name = s.name
    when not matched then insert(t.id, t.name) values(s.id, s.name)

select * from test;

        ID NAME
---------- ----
         1 a   
         2     
         3 c   
         4 b   

Будет ли вышеупомянутое MERGE когда-нибудь дать сбой? Если сначала UPDATEs, а затем INSERTs, индекс / ограничение не будет аннулировано во время выполнения. Но если сначала будет INSERTs, а затем UPDATEs, индекс будет временно признан недействительным, и оператор может завершиться ошибкой ?.

Может ли кто-нибудь подробно объяснить (или указать в правильном направлении), как СУБД Oracle решает такие проблемы? Кроме того, одинакова ли обработка при использовании предложения LOG ERRORS INTO?

Основная причина, по которой я задаю этот вопрос и почему мне нужно решение: у меня есть операторы MERGE, выполняющиеся в течение нескольких часов с предложением LOG ERRORS INTO. Ведение журнала ошибок, похоже, работает как автономная транзакция. Некоторые уникальные ошибки ограничений (на основе уникальных индексов) регистрируются задолго до того, как оператор завершает обновление (среди прочего, я вижу, что последовательность растет), и я не знаю почему (хотя, в конце концов, после обновления не должно быть уникальных ограничений. признан недействительным). Когда я смотрю в таблицу ERROR, я вижу нарушение ORA-00001: уникальное ограничение (XXX.YYY) при операции INSERT. Я могу вставить эту запись из таблицы ERROR в основную таблицу, не вызывая отказа уникального ограничения. Поэтому мне интересно, почему вообще регистрируется ошибка.

РЕДАКТИРОВАТЬ: В приведенных ниже ответах утверждается, что при выполнении оператора ограничения применяются в конце оператора. Я понимаю и согласен (хотя я хотел бы узнать более подробную информацию об обслуживании индекса в таких сценариях). Чего я не понимаю и почему на этот вопрос до сих пор нет ответа, так это почему у меня регистрируются эти ORA-00001: unique constraint (XXX.YYY) нарушенные ошибки, хотя их не должно быть. Похоже, что механизм регистрации ошибок не работает атомарно.

РЕДАКТИРОВАТЬ2:

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE    11.2.0.4.0  Production
TNS for Solaris: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

EDIT3: я немного поиграл и смог воспроизвести эту ошибку:

drop table test;

drop table err_test;

create table test as (
    select 1 as id, 'a' as name from dual 
    union all 
    select 2, 'b' from dual 
    union all 
    select 3, 'c' from dual
);

create unique index ind on test(name);

alter table test add constraint constr unique (name);

--select test.rowid, test.* from test;

BEGIN
DBMS_ERRLOG.CREATE_ERROR_LOG (
   dml_table_name            => 'TEST',
   err_log_table_name        => 'ERR_TEST');
END;
/

--truncate table err_test;

select * from err_test;

merge /*+ PARALLEL(t 2) */ into test t using (
    select 4 as id, 'b' as name from dual 
    union all 
    select 2 as id, null as name from dual 
) s on (s.id = t.id) 
    when matched then update set t.name = s.name
    when not matched then insert(t.id, t.name) values(s.id, s.name)
LOG ERRORS INTO ERR_TEST('TEST,ID:'||s.id) REJECT LIMIT UNLIMITED;

select * from err_test;

В последнем select * from err_test; я всегда получаю: ORA-00001: unique constraint (XXX.CONSTR) violated. Странно то, что настоящий оператор MERGE (в производстве) больше не работает в ПАРАЛЛЕЛЬНОМ режиме, и я все еще иногда получаю эту ошибку ...

EDIT4: лучший ответ, который я пометил как принятый, хотя сам вопрос не получил полного ответа. Похоже, это просто ошибка в Oracle.


person Davor Josipovic    schedule 10.12.2014    source источник
comment
Какая точная версия базы данных у вас установлена? Metalink содержит пару документов об ошибках, связанных с MERGE и ORA-00001.   -  person Frank Schmitt    schedule 18.03.2015
comment
Алос, вы пробовали запустить MERGE без регистрации ошибок? Metalink 17449815 (для MERGE sql наблюдается несогласованность индексов с ветвями INSERT и UPDATE, также может быть указано ERROR LOGGING (LOG ERRORS INTO clause)).   -  person Frank Schmitt    schedule 18.03.2015
comment
@FrankSchmitt Хорошая идея увидеть в этом ошибку. Версия 11.2.0.4.0. Я разберусь с этим. Я попытался запустить его без предложения ERROR LOGGING, но ни разу не столкнулся с какими-либо ограничениями. Это производственная среда, поэтому я не могу удалять это предложение до бесконечности.   -  person Davor Josipovic    schedule 18.03.2015
comment
Первым свойством ACID транзакции является атомарность. Это означает, что либо транзакция завершается успешно и все выполненные действия фиксируются, либо она терпит неудачу в какой-то момент, и все, что было сделано, откатывается, что означает, что ничего не было сделано.   -  person Lalit Kumar B    schedule 18.03.2015


Ответы (2)


Это слияние никогда не заканчивается неудачей.

Это объясняется с примерами здесь: Основные понятия базы данных - 5 . Целостность данных

Для не подлежащих отмене ограничений (по умолчанию):

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



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



Ниже, в этой документации, вы можете найти два примера транзакций, которые «внутренне» во время своего выполнения нарушают некоторые правила ограничений, но в конце они выполняют все ограничения, и есть законные, потому что:

... потому что база данных эффективно проверяет ограничения после завершения оператора. На рис. 5-4 показано, что база данных выполняет действия всего оператора SQL перед проверкой ограничений.

В конце они также написали, что:

Примеры в этом разделе иллюстрируют механизм проверки ограничений во время операторов INSERT и UPDATE, но база данных использует один и тот же механизм для всех типов операторов DML. Один и тот же механизм используется для всех типов ограничений, а не только для самореференциальных ограничений.

person krokodilko    schedule 10.12.2014
comment
Спасибо за инициативу. Обратите внимание, что ограничения - это только часть вопроса. Обработка уникального индекса - это совсем другое дело. Я вернусь после того, как изучу эту документацию. - person Davor Josipovic; 10.12.2014
comment
Что касается ограничений, то вы абсолютно правы: они проверяются в конце оператора и не должны вызывать проблем. Но мне трудно понять, как это применимо к индексам. Индексы поддерживаются во время выполнения, и для уникальных индексов rowid не считается частью ключа. Я только что просмотрел Руководство по концепциям и Архитектуру БД Kyte, но не нашел ничего полезного об обработке индекса внутри оператора. - person Davor Josipovic; 11.12.2014
comment
Но почему вы заботитесь об обслуживании индексов во время обновления? Они четко говорят: ваш оператор SQL никогда не дает сбоев, если ограничения не будут нарушены в конце выполнения транзакции.. Транзакция базы данных должна быть ACID: en.wikipedia.org/wiki/ACID, особенно должна соответствовать с правилами согласованности - если, например, существует ограничение A+B=100, то правило не должно зависеть от порядка внутренних операций внутри транзакции. Независимо от того, является ли порядок «A + B = 100» или «B + A = 100», он должен быть успешным в обоих случаях, он не может потерпеть неудачу во втором случае «B + A = 100», потому что порядок неправильный. - person krokodilko; 11.12.2014
comment
Да, я согласен. Но удалите ограничение уникальности в приведенном выше примере (и оставьте только уникальный индекс), и оператор завершится ошибкой по уникальному индексу, а не по ограничению. Если уникальный индекс эквивалентен неотложному ограничению уникальности, тогда все в порядке, но, похоже, это не всегда так: внешние ключи могут быть созданы только на уникальных ограничениях, а не на индексах. Кроме того, индекс на основе уникальной функции не имеет эквивалента ограничения уникальности. Поэтому мне нелегко поверить, что проверка ограничений применима и к проверке индекса. - person Davor Josipovic; 11.12.2014
comment
И это еще не все. У меня MERGE операторы выполняются несколько десятков часов с предложением LOG ERRORS INTO. Журнал ошибок работает как autonomous transaction. Некоторые уникальные ошибки ограничений (на основе уникальных индексов) регистрируются задолго до того, как оператор завершает обновление (среди прочего, я вижу, что последовательность растет), и я не знаю почему (хотя, в конце концов, после обновления не должно быть уникальных ограничений. признан недействительным). Это причина моего первоначального вопроса и обслуживания уникального индекса. - person Davor Josipovic; 11.12.2014

Часть задания «ЗАПИСАТЬ ОШИБКИ В», как указали другие пользователи, происходит после выполнения оператора (части обновления и вставки), во время проверки ограничений. Таким образом, вы можете вставить ошибки до завершения проверки ограничений. Вот почему вы видите ошибку, вставленную до того, как оператор будет полностью завершен.

И как ответ на это наблюдение:

Я могу вставить эту запись из таблицы ERROR в основную таблицу, не вызывая отказа уникального ограничения. Поэтому мне интересно, почему вообще регистрируется ошибка.

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

(Я имею в виду, что записи в части USING не находятся в одном и том же утверждении.

  • сессия 1: слияние с использованием select 4 as id, 'b' as name from dual (ошибка вставляется в журнал)
  • сессия 2: слияние с использованием select 2 as id, null as name from dual commit ok
  • сессия 3: вы снова пытаетесь вставить вставку, и она работает

)

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

person Florin Ghita    schedule 20.03.2015
comment
Afaik, никакой другой оператор не манипулирует таблицей. Из сообщения ora_err_tag $ таблицы ERR я могу сделать вывод, что вышеуказанный оператор MERGE вызывает сбой. Тем не менее, у вас есть несколько веских аргументов. Я посмотрю на них. Я также обновил свой вопрос (edit3). - person Davor Josipovic; 20.03.2015