Предположим, у меня есть следующая таблица со следующими ограничениями:
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
когда-нибудь дать сбой? Если сначала UPDATE
s, а затем INSERT
s, индекс / ограничение не будет аннулировано во время выполнения. Но если сначала будет INSERT
s, а затем UPDATE
s, индекс будет временно признан недействительным, и оператор может завершиться ошибкой ?.
Может ли кто-нибудь подробно объяснить (или указать в правильном направлении), как СУБД 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.