Oracle: statement-level write consistency question.

J.K.
Уже с Приветом
Posts: 711
Joined: 18 Jun 2003 06:58
Location: su/us

Re: Oracle: statement-level write consistency question.

Post by J.K. »

tengiz wrote:Проверено на Oracle 9i, 8i. Setup:

Code: Select all

rollback;
drop table fruits;
create table fruits
(
  bin int primary key,
  amount int default (0) not null,
  pending int default (0) not null,
  cleared date default (sysdate) null
)
/
alter table fruits add (
  constraint ck1 check (amount >= 0),
  constraint ck2 check (amount + pending >= 0),
  constraint ck3 check (
    (pending = 0 and cleared is not null)
       or (pending <> 0 and cleared is null))
)
/
create or replace trigger FruitsInsUpd before insert or update on fruits
for each row
begin
 if :new.pending = 0 and :new.cleared is null or
    :new.pending <> 0 and :new.cleared is not null then
   raise_application_error (-20101, 'invalid combination of .cleared and .pending');
 end if;
end;
/
begin
  insert into fruits (bin, amount, pending, cleared) values (1, 10, -2, null);
  insert into fruits (bin, amount, pending, cleared) values (2,  0,  2, null);
  insert into fruits (bin, amount, pending) values (3,  0,  0);
  commit;
end;
/
select * from fruits;
...
       BIN     AMOUNT    PENDING CLEARED
---------- ---------- ---------- ---------
         1         10         -2
         2          0          2
         3          0          0 03-NOV-03

Затем в SQL*Plus сессии 1:

Code: Select all

begin
  update fruits set pending = pending - 1, cleared = null where bin = 1;
  update fruits set pending = pending + 1, cleared = null where bin = 3;
end;
/
select * from fruits;
...
       BIN     AMOUNT    PENDING CLEARED
---------- ---------- ---------- ---------
         1         10         -3
         2          0          2
         3          0          1

Транзакцию в сессии 1 пока не фиксируем. В сессии 2:

Code: Select all

update fruits
set amount = amount + pending, pending = 0, cleared = sysdate
where cleared is null;

select * from fruits;

Сессия 2 заблокирована, что понятно. Теперь фиксируем транзакцию в сессии 1. Сессия 2 разблокируется, завершает update и выдаёт:

Code: Select all

       BIN     AMOUNT    PENDING CLEARED
---------- ---------- ---------- ---------
         1          7          0 03-NOV-03
         2          2          0 03-NOV-03
         3          0          1

Что, насколько я понимаю, не является результатом, который обещается Oracle - каждый отдельный оператор, включая insert/update/delete, должен увидеть и обработать согласованное состояние базы на момент начала оператора вне зависимости от уровня изоляции. Причём на READ COMMITTED, в отличие от SERIALIZABLE, момент начала отдельного оператора в Oracle подвижен (мы это обсуждали пару месяцев назад здесь на Привете) - при необходимости, это делается откатом и перезапуском оператора незаметно для пользователя. И именно поэтому на READ COMMITTED никогда не бывает видно ошибок сериализации.

В этом примере сессия 2 обновила строки 1 и 2 после того, как завершилась транзакция в сессии 1, а строка 3, как это ни странно, была обработана так, как она была на состояние до завершения транзакции в сессии 1 - т.е. сессия 2 вообще не заметила эту строку, хотя предикат в where должен был её отобрать.

Идея поставить такой опыт у меня появилась после прочтения ответов на asktom.oracle.com (см. write "consistency") на вопросы об их реализации consistent write - судя по описанию Тома как это работает, у Oracle могла бы наблюдаться такая аномалия из-за одной неаккуратно сделанной оптимизации в реализации алгоритма автоматического разрешения конфликтов записи.

Это может быть потеницально очень опасной ошибкой, которая элементарно может приводить к несогласованности данных в приложениях, ожидающих честного write consistency. С удовольствием послушаю критику, прежде чем поделиться находкой с Томом - может я всё-таки что-то упустил?


На момент начала 2-й транзакции мы работаем с ролбек сегментом. Посмотрим что там?

select * from fruits;

BIN AMOUNT PENDING CLEARED
---------- ---------- ---------- ---------
1 10 -2
2 0 2
3 0 0 04-NOV-03

Теперь мы говорим
update fruits
set amount = amount + pending, pending = 0, cleared = sysdate
where cleared is null;

Естественно для 2-й транзакции мы хотим обновить 1 и 2ю запись, но никак не 3-ю. Правильно?

что и получаем.
BIN AMOUNT PENDING CLEARED
---------- ---------- ---------- ---------
1 7 0 03-NOV-03
2 2 0 03-NOV-03
3 0 1

если следовать логике первой транзакции, во второй транзакции мы должны поступить так:

update fruits
set amount = amount + pending, pending = 0, cleared = sysdate
where bin=3;

Отпускаем первую транзакцию

Смотрим вторую.

SQL> select * from fruits;

BIN AMOUNT PENDING CLEARED
---------- ---------- ---------- ---------
1 10 -3
2 0 2
3 1 0 04-NOV-03

То что нужно? На мой взглыд да.

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

Наперстки....Следите за пальцами.

Так как работают остальные DB ? Кто кривой ?
User avatar
tengiz
Уже с Приветом
Posts: 4468
Joined: 21 Sep 2000 09:01
Location: Sammamish, WA

Re: Oracle: statement-level write consistency question.

Post by tengiz »

J.K., правильный ответ:

Code: Select all

       BIN     AMOUNT    PENDING CLEARED
---------- ---------- ---------- ---------
         1          7          0 04-NOV-03
         2          2          0 04-NOV-03
         3          1          0 04-NOV-03

В противном случае изоляция транзакций - это фикция.
Cheers
User avatar
Dmitry67
Уже с Приветом
Posts: 28294
Joined: 29 Aug 2000 09:01
Location: SPB --> Gloucester, MA, US --> SPB --> Paris

Post by Dmitry67 »

Ох, как не хочется людям признавать очевидное ! :)
Зарегистрированный нацпредатель, удостоверение N 19719876044787 от 22.09.2014
User avatar
Dmitry67
Уже с Приветом
Posts: 28294
Joined: 29 Aug 2000 09:01
Location: SPB --> Gloucester, MA, US --> SPB --> Paris

Re: Oracle: statement-level write consistency question.

Post by Dmitry67 »

tengiz wrote:С удовольствием послушаю критику, прежде чем поделиться находкой с Томом - может я всё-таки что-то упустил?


Еще не постили ?

P.S. Интересно, а если у Вас есть лицензия Oracle, что если обратиться в support и поиметь терпение преодолеть первые бастионы supportа для идиотов ?
Зарегистрированный нацпредатель, удостоверение N 19719876044787 от 22.09.2014
User avatar
tengiz
Уже с Приветом
Posts: 4468
Joined: 21 Sep 2000 09:01
Location: Sammamish, WA

Re: Oracle: statement-level write consistency question.

Post by tengiz »

Dmitry67 wrote:Еще не постили ?

P.S. Интересно, а если у Вас есть лицензия Oracle, что если обратиться в support и поиметь терпение преодолеть первые бастионы supportа для идиотов ?

Нет, ещё не постил. У него там backlog, поэтому он новые вопросы пока не принимает. Но чтобы время зря не терять, можно здесь на Привете обкатать и побить об углы простую и понятную аргументацию.

Лицензии у меня нет - я просто скачал обе версии оракла с сайта производителся и балуюсь у себя на домашней машине. Да и потом саппорт - это, боюсь, не то место, где можно поговорить об индукции с дедукцией. У них - продукция.
Cheers
J.K.
Уже с Приветом
Posts: 711
Joined: 18 Jun 2003 06:58
Location: su/us

Re: Oracle: statement-level write consistency question.

Post by J.K. »

tengiz wrote:J.K., правильный ответ:

Code: Select all

       BIN     AMOUNT    PENDING CLEARED
---------- ---------- ---------- ---------
         1          7          0 04-NOV-03
         2          2          0 04-NOV-03
         3          1          0 04-NOV-03

В противном случае изоляция транзакций - это фикция.


Sorry for translit.

Izolation Row or Table ?

But, 2-a transaction zablokirovala 1 & 2 record v ozhidanii 1-y transaction, na 3-y record 2-y transaction _nachixat'_ na dannay moment. I eto pravil'no. Nachalo 1-y & 2-y transaction proizoshlo practicheski odnovremenno. 2-y transaction dolzhna obnovit' 1 & 2 record!!!, but not 3-y.
A ti xochesh skazat' chto nachalo 2-y transaction dolzhno nachinat'sya posle okonchania 1-y - eto nepravil'no.

Xotya, Tengiz, ya tvoy point ponimayu, no ne schitayu, chto eto verno. Eto ne Bug, eto philosophy.
User avatar
Dmitry67
Уже с Приветом
Posts: 28294
Joined: 29 Aug 2000 09:01
Location: SPB --> Gloucester, MA, US --> SPB --> Paris

Re: Oracle: statement-level write consistency question.

Post by Dmitry67 »

tengiz wrote:Да и потом саппорт - это, боюсь, не то место, где можно поговорить об индукции с дедукцией. У них - продукция.


Тенгиз, пять баллов за фразу !
Зарегистрированный нацпредатель, удостоверение N 19719876044787 от 22.09.2014
zVlad
Уже с Приветом
Posts: 15409
Joined: 30 Apr 2003 16:43

Post by zVlad »

Поведение Оракл в самом первом сценарии Tengiza может быть интерпретированно следующим образом:
На начальном этапе выполнения - процессировании WHERE clause - Update второй сессии (впрочем любой update) работает как SELECT в read-only версионнике и намечает строки для процессирования.
В выбранный набор попадают 1 и 2 строки. Третья строка в этот набор не попадает, потому что ее данные до начала первой, незакоммиченной сесии, не удовлетворяют критерию второго UPDATE.
На втором этапе - собственно изменение - второй UPDATE обнаруживает выбранную первую строку заблокированной и переходит в ожидание переодически просыпаясь и проверяя - не освободилась ли нужная ему строка. Проснувшись в очередной раз второй UPDATE находит строки 1 и 2 не залокированными и модифицирует их.

В рамках приведенного выше объяснения, иначе говоря с точки зрения версионного подхода к решению проблем concurrency, а точнее Оракловского понимания версионного подхода, результат полученный в эксперименте - правильный результат. Что и отстаивают представители команды "Оракл".

С точки же зрения блокировочного (изоляционного) подхода результат не верен, потому что согласно этому подходу второй UPDATE должен был ждать пока первый не снимет замок со строк 1 и 3 и только затем проверять соответствуют ли эти строки критерию в WHERE clause.

Мне так кажется, что в Оракл для процессирования where используется один и тот же код во всех случаях. И этот код использует UNDO сегмент. Кое-какие явные недостатки такого обобщения устранены через ре-старт, который работает не для всех случаев, что и позволяет иметь накладки приведенные в обсуждаемом сценарии.

Вот если Оракл удалит из своей документации ссылки на уровни изоляции, то тогда к Ораклу вообще никаких притензий не будет. Можно будет просто говорить: есть базы данных, обеспечивающие конкуренцию через изоляцию, и Оракл.
User avatar
Dmitry67
Уже с Приветом
Posts: 28294
Joined: 29 Aug 2000 09:01
Location: SPB --> Gloucester, MA, US --> SPB --> Paris

Post by Dmitry67 »

Мне кажется что результат может быть верным или нет
Какой подход использован для его получения вообще не важно
При оценке корректности результата базу надо рассматривать вообще как черный ящик. Непонятно, как объяснение деталей имплементации и рассуждения о замках может заставить поверить что неправильный результат - правильный.

tengiz, а можете придмать на основе этого более практический пример, ну например что нибудь вроде есть банк, в банке со счета на счет трензакции перебрасывают деньги. Общая сумма при этом остается неизменной. Если бы удалось построить кверь нарушающую некий инвариант (сумма денег на всех счетах константа) то вот это и было бы стопроцентно показательным неправильным результатом, против которого уже не попрешь
Зарегистрированный нацпредатель, удостоверение N 19719876044787 от 22.09.2014
User avatar
camel
Новичок
Posts: 86
Joined: 06 Dec 2002 18:21

Post by camel »

Мое представление, возможно несколько упрощенное, того, как работает UPDATE в оракле.

Команда UPDATE выполняется в два этапа - поиск строк и их модификация.

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

Если найденные строки - кандидаты на обновление в момент t1 заблокированы другой незавершенной транзакцией, второй этап выполнения UPDATE откладывается до снятия этих блокировок, т.е. до момента t2.

После снятия блокировок от других транзакций, в момент t2, выполняется второй этап UPDATE - модификация текущих в этот момент версий строк-кандидатов, причем проверяется, чтобы критерий WHERE все еще выполнялся, иначе строка обновлена не будет.

В некоторых случаях в момент t2 оракл выполняет повторный поиск строк для обновления, что на первый взгляд запутывает картину, но по-существу ничего не меняет, потому что это просто переносит момент начала всей команды UPDATE с t1 на t2.

Основным моментом, вызывающим дискуссию, по-видимому является то, что поиск строк выполняется в момент t1, когда изменения от других транзакций еще не зафиксированы и поэтому не видны, а обновление строк происходит в момент t2, когда эти изменения уже видны. Естественно, что строки уже не те, которые были в момент их поиска. Это может привести к проблемам типа "lost update", что логически вполне понятно. Там, где этот риск неприемлем, следует использовать SELECT FOR UPDATE или SERIALIZABLE.
vc
Уже с Приветом
Posts: 664
Joined: 05 Jun 2002 01:11

Post by vc »

Tengiz,

Let me respond to your two posting at one go ...

tengiz wrote:Here's another one - what if there is no predicate at all? Do you believe that in this case Oracle should never re-scan? If so, then how would you like the following scenario. Session 1:

Code: Select all

drop table a;
create table a
(
   pk int primary key,
   fk int null,
   data int null,
   constraint c_fk foreign key (fk) references a (pk)
);
insert into a values (1, null, null);
commit;
select * from a;

insert into a values (2, 1, null);
update a set fk = 2 where pk = 1;
select * from a;
...
        PK         FK       DATA
---------- ---------- ----------
         1
...
        PK         FK       DATA
---------- ---------- ----------
         1          2
         2          1
Session 2:

Code: Select all

update a set data = fk;
select * from a;
commit;
Session 1:

Code: Select all

commit;
Session 2:

Code: Select all

        PK         FK       DATA
---------- ---------- ----------
         1          2          2 <-- looks like we did see the latest committed state.
         2          1            <-- nope, not true for this one

Do you believe that the result produced by session 2 is consistent? If so, then I
rest my case.


This case is no different from the cases you've presented earlier. Without a predicate, the conceptual 'consistent select' will select the whole table as of the point in time Session 2's update was issued, hence, only one row is updated. No surprise here, right ? As to my belief, see below.

tengiz wrote:Now, if in the session 2 instead of <update a set data = fk> you'd issue <update a set pk = pk, data = fk>, the result would be different:

Code: Select all

        PK         FK       DATA
---------- ---------- ----------
         1          2          2
         2          1          1

And this is consistent indeed.


This is not surprising either -- the locked low predicate column changed causing Sessio 2's transaction abort and restart.

In your previous posting you wrote:

tengiz wrote:vc, возможно я, как всегда, нечётко выражаюсь. Попробую слегка по-другому:

Я прекрасно понимаю, что делает Oracle. Ваши объяснения как это происходит не вызывают у меня почти никаких возражений. Проблема в том, что я считаю, что то что делает Oracle: во-первых, неправильно; во-вторых, не соответствует тому, что обещано в документации.

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


Atomic transaction .. A mighty big word. Let's apply some defintion to it and see if Oracle satisfies it:
"a transaction is a unit of operation. It's atomic, i.e. either all the transaction's actions are completed or none are". That's all.
Surely Oracle conforms to the definition -- we have not observed partial rollbacks or commits yet, right ? I do not believe you showed that Oracle sees "a half fixed transaction".

Let's recall, for the benefit of those who might be reading this stuff, how Oracle performs an update/delete. A consistent set of rows is selected based on the predicate, if any, and the timestamp (each Oracle block has one) corresponding to the point in time the update statement was issued.

Say, we have two transactions A and B. Transaction A issues an update statement with the T1 timestamp and the isolation level is READ COMMITTED. When A arrives to some row, it discovers that the row is locked because B has already updated it. A blocks and waits until B commits. After B commits, there are two possible outcomes:

Case 1. The predicate value for the locked row did not change. Transaction A proceeds to update the set of rows it selected at T1. What people are usually upset about is the fact that A does not pick up the _new_ rows satisfying A's predicate. However, the READ COMMITTED isolation level never promised that, non-repeatable reads are the phenomenon explicitly allowed by this IL both in SLQ'92 and '99. How this situation is different in comparison to the case when a simple select statement runs and another transaction added/deleted/modified some rows whilst the select was being executed ? One would get exactly the same situation as with updates, namely non-repeatable reads.

Case 2. The predicate value changed. Transaction A has no other choice but to abort because it 'lost' the locked row it was going to operate on -- the original selection as of T1 is no longer consistent precisely because of the row loss. So transaction A rolls back all the changes it might have made and starts from scratch using the new T2 timestamp as of the point in time when B committed. In Case 2, getting new rows, if any, is a side benefit, not a requirement.

In both cases Oracle operates over a consistent selection, in Case 1 as of T1 and in Case B as of T2. In none of the above cases, a partially committed set of rows is used.

Demanding that A should behave in Case 1 in the same way as it did in Case 2 would be a call for REAPEATABLE READS which can be accomplished by
a) running the update transaction in Oracle's Serializable mode;
or
b) using pessimistic locking via SELECT FOR UPDATE;
or
c) implementing optimistic locking via timestamping or checksumming.

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


I do not think you presented a convincing proof of the purported defect, and I am easy to convince, just recall our discussion of whether Oracle's Serializable is really serializable ( No). At least, show where exactly the RC contract is violated.

tengiz wrote:Попробуйте, кстати, проделать такой же опыт на SQL Server или Sybase.


If we want to decide whether a specific implementation is 'good enough', we must use a common yardstick, like ACID, isolation levels etc. Specific implementation pecularities are irrelevant in this context, although very important in their own right if we want to use a specific implementation to its fullest.
Besides, I do not like, in general, database pissing contests. After all, it's just a tool more or less suitable for a specific task(s).

However, to spice up a little our discussion, here's a little tit-for-tat:

Under our favourite isolation level READ COMMITTED, no blocking database (Sybase, DB2, etc.), guarantees correct results for such simple queries as
'select sum(val) from t1 <predicate>'.
They may and sometimes will return bogus results that have at no point in time, ever existed in the database. Now, that's really 'inconsistent', right ? ;)

Rgds.
Last edited by vc on 05 Nov 2003 18:56, edited 1 time in total.
vc
Уже с Приветом
Posts: 664
Joined: 05 Jun 2002 01:11

Post by vc »

camel wrote:Мое представление, возможно несколько упрощенное, того, как работает UPDATE в оракле.

Команда UPDATE выполняется в два этапа - поиск строк и их модификация.

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

Если найденные строки - кандидаты на обновление в момент t1 заблокированы другой незавершенной транзакцией, второй этап выполнения UPDATE откладывается до снятия этих блокировок, т.е. до момента t2.

После снятия блокировок от других транзакций, в момент t2, выполняется второй этап UPDATE - модификация текущих в этот момент версий строк-кандидатов, причем проверяется, чтобы критерий WHERE все еще выполнялся, иначе строка обновлена не будет.

В некоторых случаях в момент t2 оракл выполняет повторный поиск строк для обновления, что на первый взгляд запутывает картину, но по-существу ничего не меняет, потому что это просто переносит момент начала всей команды UPDATE с t1 на t2.

Основным моментом, вызывающим дискуссию, по-видимому является то, что поиск строк выполняется в момент t1, когда изменения от других транзакций еще не зафиксированы и поэтому не видны, а обновление строк происходит в момент t2, когда эти изменения уже видны. Естественно, что строки уже не те, которые были в момент их поиска. Это может привести к проблемам типа "lost update", что логически вполне понятно. Там, где этот риск неприемлем, следует использовать SELECT FOR UPDATE или SERIALIZABLE.


Your understanding of how, conceptually, an update is executed is absolutely correct.

Rgds.
J.K.
Уже с Приветом
Posts: 711
Joined: 18 Jun 2003 06:58
Location: su/us

Post by J.K. »

camel wrote:Основным моментом, вызывающим дискуссию, по-видимому является то, что поиск строк выполняется в момент t1, когда изменения от других транзакций еще не зафиксированы и поэтому не видны, а обновление строк происходит в момент t2, когда эти изменения уже видны. Естественно, что строки уже не те, которые были в момент их поиска. Это может привести к проблемам типа "lost update", что логически вполне понятно. Там, где этот риск неприемлем, следует использовать SELECT FOR UPDATE или SERIALIZABLE.


Совершенно верно, речь идет только о начале транзакции.
Oracle автоматически открывает транцакцию при Update, Delete, Insert, Select for update set transaction read only.
По умолчанию Oracle работает со строками а не с таблицей.

Если мы хотим получить тот результат о котором мечтает автор, то мы должны заблокировать таблицу во второй тарнщакции и когда она будет разблокирована, начнеться второй update (В общем-то как это делает SQL SERVER & др.), будет happy end of this story.

По моему это неправильно блокировать всю таблицу перед выбором строк. Почему я должен кого-то ждать если мне нужен другой кортеж?
User avatar
tengiz
Уже с Приветом
Posts: 4468
Joined: 21 Sep 2000 09:01
Location: Sammamish, WA

Post by tengiz »

Dmitry67 wrote:tengiz, а можете придмать на основе этого более практический пример, ну например что нибудь вроде есть банк, в банке со счета на счет трензакции перебрасывают деньги. Общая сумма при этом остается неизменной. Если бы удалось построить кверь нарушающую некий инвариант (сумма денег на всех счетах константа) то вот это и было бы стопроцентно показательным неправильным результатом, против которого уже не попрешь

Тот самый пример, который я приводил в первом сообщении, как раз и был попыткой соорудить реальный случай с инвариантом. В качестве инварианта выступает сумма колонки pending - так как делается переброска фруктов из корзины в корзину, то эта сумма в любой момент времен должна быть равна нулю. Все транзакции в примере сделаны так, чтобы этот инвариант сохранялся - в этом легко убедиться. Однако, конечный результат показывает, что Oracle этого не обеспечил. Когда я попытался защитить этот инвариант констрейнтом, чтобы нарушения явно ловились, оказалось, что я не знаю элементарного решения для такой задачки в случае Oracle. В SQL Server, как Вы прекрасно знаете, для этого просто делается триггер, считающий сумму этой колонки в inserted и deleted, если сумма не равна нулю, то ошибка и откат. Вариант Oracle - это for each row триггер, который собирает эти суммы строка за строкой. Я посчитал, что это усложнит элементарный пример, поэтому я и не стал с этим связываться.
Cheers
User avatar
tengiz
Уже с Приветом
Posts: 4468
Joined: 21 Sep 2000 09:01
Location: Sammamish, WA

Post by tengiz »

vc, по третьему кругу повторять одно и то же мне уже смысла мало, поэтому только пара замечаний:
This is not surprising either -- the locked low predicate column changed causing Sessio 2's transaction abort and restart.

Может, я опять сопроводил свой пример нечёткими объяснениями? В этом примере нет предикатов вообще. И почему, как Вы полагаете, Oracle решил перестартовать оператор, если его внутренняя логика работы позволяет ему этого не делать? Напоминаю, что во всех остальных случаях, перезапуск делался только при изменении значения колонки входящей в предикат. В этом примере - во-первых, нет предиката вообще; во-вторых, и значение колонки, в действительности, не меняется - <update a set data = fk> не вызывает перезапуска, а <update a set pk = pk, data = fk>, как это ни странно, вызывает. Можете объяснить почему?

Теперь по поводу Ваших рассуждений о стандарте и пр:

1. Если Вам не кажется убедительным, что любой одиночный update оператор не должен оставлять за собой строки, не соответствующие ни одному зафиксированному состоянию, то здесь больше говорить не о чем. Моего красноречия явно не хватило, sorry.

2. READ COMMITTED в Oracle, согласно документации Oracle - это больше, чем ANSI READ COMMITTED. А именно, read consistency и write cosistency на уровне отдельного оператора, под отдельным оператором, на самом деле, понимается всё, что это оператор автоматически может вызвать, включая весь код в триггерах. Поэтому ссылаться на стандарт, как на объяснение почему реально не обеспечивается обещанное документацией - просто несерьёзно, согласитесь.

3. Маленькая поправка - REPEATABLE READ не устраняет фантомы, Вы это разумеется прекрасно знаете, поэтому я полагаю, что в Ваших рассуждениях о том, как сделать так, чтобы новая строка, удовлетворяющая предикату попала или не попала в выборку упоминание REPEATABLE READ - простая оговорка.
Cheers

Return to “Вопросы и новости IT”