(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Алгоритм "мини-откатов" в Oracle или еще раз о Write Consistency. Часть 1

Источник: oracle

Введение

Как-то раз, бродя по просторам Интернета, я в очередной раз увидел ссылку на сайт Тома Кайта [1]. Обнаружив, что Том продолжил дискуссию циклом небольших статей на эту тему, я тоже решил заняться исследованием этой весьма непростой и мало изученной проблемы - неявным перезапуском команды update в случае, когда другие сеансы одновременно модифицируют данные обновляемой таблицы. Кроме того, как я заметил, подавляющее большинство разработчиков и администраторов даже и не подозревают о существовании таких перезапусков DML-команд и команды select for update, которые могут очень существенно повлиять на логику и производительность приложений. А если они и знают о них, то не в полной мере. Такие неявные, выполняемые Oracle перезапуски команд, я буду далее называть "мини-откатами".

Одним из моих любимых занятий является изучение всякого рода дампов и трассировочных файлов. На мой взгляд, это сильно помогает в понимании принципов и алгоритмов работы любой системы. Кроме того, мне кажется, что только зная как и почему это работает именно так, а не иначе, можно строить эффективно работающие системы и писать высокопроизводительные приложения. При этом абсолютно не важно, относится ли сказанное к СУБД Oracle, операционной системе или вообще, скажем, к работе двигателя внутреннего сгорания. Поэтому я выбрал немного другой способ для выяснения того, что же происходит в обсуждаемом Томом и посетителями его сайта случае - изучение трассировочной информации, которую может предоставить Oracle. Эта информация даст нам возможность более детально разобраться в алгоритмах работы ядра Oracle. Кроме того, такой способ не требует для обнаружения "мини-откатов" использования триггеров, автономных процедур и т.д., что может так или иначе повлиять на чистоту экспериментов.

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

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

Объяснение и обсуждение причин такого поведения Oracle, то есть, почему это работает так, а не иначе, в мои планы не входит, так как их уже постарался изложить Том Кайт. Почитать его комментарии можно, пройдя по ссылкам, указанным в [1]-[4]. Поэтому основной целью этой статьи будет показать, как это работает, то есть сам алгоритм "мини-откатов" и альтернативный способ его изучения с использованием некоторых недокументированных возможностей. Кроме того, я постараюсь также дать несколько рекомендаций по возможности уменьшения влияния "мини-откатов" на производительность приложений.

Что такое "мини-откат"?

Итак, суть проблемы. В нашей многопользовательской системе имеется достаточно большая таблица. Причем, не важно, секционированная ли это таблица, индекс-организованная и т.д., имеет ли она индексы или нет - сути это не меняет. В одном из сеансов мы запустили на выполнение в режиме изолированности READ COMMITED, принятом в Oracle по умолчанию, команду update, указав во фразе WHERE (так называемом предикате) условие, по которому будут выбираться строки, подлежащие обновлению. После того, как началось выполнение команды update, другой сеанс обновил или удалил одну или более строк, которые удовлетворяли предикату команды update первого сеанса на момент начала ее выполнения, но до изменения которых тот еще не успел дойти (разумеется, уже обновленные первым сеансом строки заблокированы и не могут никем модифицироваться). При этом:

  1. изменения и удаления строк вторым сеансом были зафиксированы до того момента, когда первый сеанс, выполняющий команду update, добрался до этих измененных строк, либо когда он дошел до заблокированной вторым сеансом строки и был вынужден ждать фиксации изменений вторым сеансом;
  2. измененные вторым сеансом строки на начало выполнения первым сеансом команды update удовлетворяли условию, по которому происходит обновление (удовлетворяли предикату), а после модификации перестали ему удовлетворять.

В этом случае Oracle произведет "мини-откат": неявно перезапустит команду update и выполнит обновление уже нового набора строк. Если же в момент выполнения команды update происходит вставка новых (даже удовлетворяющих предикату) строк другими сеансами, то перезапуска команды не будет. Происходит это потому, что выполнение команды update состоит из двух фаз:

1) согласованное чтение ( consistent read ) таблицы на момент начала выполнения команды для нахождения строк, подлежащих модификации (в том числе удовлетворяющих предикату, если он задан);
2) чтение блоков данных таблицы в текущем ( current read ) режиме для модификации найденных на предыдущей фазе строк.

Поэтому все новые строки, которые были вставлены в таблицу другими сеансами после начала выполнения команды UPDATE, "не видны" во время первой фазы команды update даже несмотря на фиксацию (COMMIT) таких вставок. Но, как мы увидим позже, это уже не так, если производится "мини-откат" этих команд.

Кроме того, "мини-откаты" могут возникать при выполнении команд DELETE, MERGE и SELECT FOR UPDATE. Так как в каждом случае существует достаточно много нюансов, то об этом я постарался рассказать в конце статьи, описав алгоритм "мини-откатов" для каждой из команд в отдельности.

Как будет проводиться тестирование

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

Event 10219 - "monitor multi-pass row locking" ("отслеживать многопроходные блокировки строк"). Это событие включает запись в трассировочный файл серверного процесса, с которым соединен пользователь, диагностической информации при возникновении исследуемой нами ситуации в случае, если выполняется команда update или фаза update команды merge. Level 2 и выше включает выдачу информации об обновляемых строках.

Event 10218 - "dump uba of applied undo" ("выдавать uba применяемых undo -записей"). Включение этого события позволяет получать в трассировочном файле uba -адреса ( uba - Undo Block Address) блоков, просмотренных и примененных при откате транзакции или команды (при явном откате после выдачи команды ROLLBACK или при неявном откате команды, например, при возникновении ошибки ORA-00001: unique constraint и ей подобных).

Event 10200 - "consistent read buffer status" ("статус буфера при выполнении согласованного чтения"). При выполнении согласованного чтения блока данных (не заголовков сегментов и прочих "служебных" блоков) выдает в трассировочный файл список и статус всех копий (клонов) этого блока, находящихся в буферном кэше.

Event 10228 - "trace application of redo by kcocbk" ("отслеживать применение информации повтора в программе kcocbk"). Записывает в трассировочный файл в пригодном для анализа виде всю redo -информацию, генерируемую серверным процессом.

Теперь приступим к тестированию. Большей частью тесты мной проводились на Oracle 9.2.0.7EE. Часть из них повторялась на Oracle 8.1.7.4 и 10.1.0.4 и показала идентичность алгоритмов. Все трассировочные файлы получены при выполнении тестов на Oracle 9.2.0.7EE. При выполнении тестов на других версиях Oracle ваши трассировочные файлы, возможно, будут немного отличаться.

Для упрощения понимания я постарался не сильно отклоняться от тестов, которые приводились на сайте Тома Кайта, но ввел еще один сеанс с целью демонстрации дополнительных тонкостей и нюансов "мини-откатов". В начале каждого теста я буду заново создавать таблицу wc_test в табличном пространстве с размером блока 4k, управляемом локально, с одинаковым размером экстента и с ручным (при помощи freelists ) управлением свободным пространством внутри сегмента (это не обязательные требования, просто они упростят нам обработку полученной информации). В каждом тесте будут запускаться несколько сеансов одного и того же пользователя. Идентификация сеансов будет осуществляться при помощи строки приглашения в SQL*Plus. С этой целью была использована утилита SQL*Plus 10.1.0.4.0 от версии Oracle 10g, которая позволяет легче и нагляднее осуществлять модификацию строки приглашения.

Тест 1 (с минимально достаточным объемом
трассировочной информации)

В первом тесте у меня будет 4 сеанса, запущенных от имени одного и того же пользователя. Первый сеанс - "Blocker" - будет создавать тестовую таблицу, наполнять ее данными и блокировать командой update строку с id =3, при этом не изменяя в ней данных. Этот сеанс предназначен только для имитации продолжительности выполнения команды update во втором сеансе - "Long update", который обновляет по условию таблицу wc_test (то есть, в команде UPDATE есть фраза WHERE - предикат) и который каждый раз будет останавливаться при попытке обновления строки с id =3, заблокированной сеансом "Blocker". После этого у нас будет время для того, чтобы в двух оставшихся сеансах мы смогли произвести в wc_test некоторые модификации до окончания команды update в "Long update". Столбец filler в таблице wc_test добавлен с той целью, чтобы в каждый блок данных помещалось ровно по 3 строки таблицы. Сделано это исключительно только для того, чтобы нагляднее показать все процессы, происходящие в сеансе "Long update".

После того, как сеанс "Long update" будет заблокирован, в третьем сеансе "First/Last" мы изменим строки в таблице wc_test и зафиксируем изменения таким образом, что, во-первых, строка с id =1, которую сеанс "Long update" пропустил как не удовлетворяющую предикату при выполнении команды update, теперь будет удовлетворять этому предикату, а строка с id =5 теперь не будет ему удовлетворять. Как мы увидим, изменение строки с id =5 вызовет "мини-откат" команды update в сеансе "Long update".

Кроме того, в этом тесте я ввел четвертый сеанс "New rows", который вставляет новые строки в таблицу wc_test , которые удовлетворяют предикату тестируемой команды. Эти строки вставляются после начала команды update в сеансе "Long update". Моя цель в этом случае - показать, что, во-первых, эти строки после "мини-отката" будут изменены сеансом "Long update". Во-вторых, что блокировка строк сеансом "Long update" после "мини-отката", вполне возможно, будет происходить неоднократно.

Для наглядности и уменьшения размера трассировочного файла в этом тесте включим только трассировку событий 10218 и 10219.

Итак, результаты теста:

Листинг 1

SQL> --Session "Blocker"
SQL> conn scott/tiger@o92
Connected.
SQL> set sqlprompt "_USER'-Blocker'> " wrap off linesize 100
SCOTT-Blocker> create table wc_test tablespace uniform_64k_block_4k as
  2    select rownum id, rownum+10 y, cast(username as char(1000)) filler
  3    from all_users where rownum <= 9;

Table created.

SCOTT-Blocker> column id          format 99
SCOTT-Blocker> column y           format 99
SCOTT-Blocker> column hex_dump_id format a18
SCOTT-Blocker> column hex_dump_y  format a22
SCOTT-Blocker> column file#       format 9999
SCOTT-Blocker> column block#      format 99999999
SCOTT-Blocker> column row#        format 9999
SCOTT-Blocker> column dba         format 99999999
SCOTT-Blocker> column hex_dba     format a8
SCOTT-Blocker> select id, y, dump(id,16) hex_dump_id, dump(y,16) hex_dump_y,
  2    dbms_rowid.rowid_relative_fno(rowid) file#,
  3    dbms_rowid.rowid_block_number(rowid) block#,
  4    dbms_rowid.rowid_row_number(rowid)   row#,
  5    dbms_utility.make_data_block_address(dbms_rowid.rowid_relative_fno(rowid),
  6      dbms_rowid.rowid_block_number(rowid)) dba,
  7    to_char(dbms_utility.make_data_block_address(dbms_rowid.rowid_relative_fno(rowid),
  8      dbms_rowid.rowid_block_number(rowid)),'FMxxxxxxxx') hex_dba
  9    from wc_test;

 ID   Y HEX_DUMP_ID        HEX_DUMP_Y             FILE#    BLOCK#  ROW#       DBA HEX_DBA
--- --- ------------------ ---------------------- ----- --------- ----- --------- -------
  1  11 Typ=2 Len=2: c1,2  Typ=2 Len=2: c1,c         10        18     0  41943058 2800012
  2  12 Typ=2 Len=2: c1,3  Typ=2 Len=2: c1,d         10        18     1  41943058 2800012
  3  13 Typ=2 Len=2: c1,4  Typ=2 Len=2: c1,e         10        18     2  41943058 2800012
  4  14 Typ=2 Len=2: c1,5  Typ=2 Len=2: c1,f         10        19     0  41943059 2800013
  5  15 Typ=2 Len=2: c1,6  Typ=2 Len=2: c1,10        10        19     1  41943059 2800013
  6  16 Typ=2 Len=2: c1,7  Typ=2 Len=2: c1,11        10        19     2  41943059 2800013
  7  17 Typ=2 Len=2: c1,8  Typ=2 Len=2: c1,12        10        20     0  41943060 2800014
  8  18 Typ=2 Len=2: c1,9  Typ=2 Len=2: c1,13        10        20     1  41943060 2800014
  9  19 Typ=2 Len=2: c1,a  Typ=2 Len=2: c1,14        10        20     2  41943060 2800014

9 rows selected.

SCOTT-Blocker> update wc_test set y=y where id=3;

1 row updated.

SCOTT-Blocker>

Листинг 2

SQL> --Session "Long update"
SQL> conn scott/tiger@o92
Connected.
SQL> set sqlprompt "_USER'-Long update'> "
SCOTT-Long update> alter session set max_dump_file_size
                                            = unlimited tracefile_identifier='Long_Test_1';

Session altered.

SCOTT-Long update> alter session set events '10218 trace name context forever, level 10:
  2    10219 trace name context forever, level 10';

Session altered.

SCOTT-Long update> 
--alter session set events '10200 trace name context forever:10228 trace name context forever';
SCOTT-Long update> update wc_test set y=88 where y=15 or id in(2,3,4) 
--Мы ждем... ;

Сеанс "Long update" ждет завершения транзакции в сеансе "Blocker".

Теперь в сеансе "First/Last" производим модификации и сразу же фиксируем изменения. После этого, когда "Long update" доберется до строки с id =5, он обнаружит, что на момент старта команды update эта строка удовлетворяла предикату (то есть, должна быть изменена, так как y =15 на момент старта команды), но в данный момент она не удовлетворяет предикату, так как y =99 и транзакция, изменившая это значение, уже зафиксировала изменения:

Листинг 3

 

SQL> --Session "First/Last"
SQL> conn scott/tiger@o92
Connected.
SQL> set sqlprompt "_USER'-First/Last'> "
SCOTT-First/Last> update wc_test set y=15 where id=1;

1 row updated.

SCOTT-First/Last> update wc_test set y=99 where id=5;

1 row updated.

SCOTT-First/Last> commit;

Commit complete.

SCOTT-First/Last>

В сеансе "New rows" вставляем 3 новые строки, удовлетворяющие предикату "Long update" ( y =15), фиксируем транзакцию, после чего модифицируем строку с id =10 так, что она теперь не удовлетворяет предикату. Обновление вызовет блокировку "Long update", когда тот дойдет до строки с id =10. Это обновление пока не фиксируем:

Листинг 4

 

SQL> --Session "New rows"
SQL> conn scott/tiger@o92
Connected.
SQL> set sqlprompt "_USER'-New rows'> "
SCOTT-New rows> insert into wc_test values(10,15,' ');

1 row created.

SCOTT-New rows> insert into wc_test values(11,15,' ');

1 row created.

SCOTT-New rows> insert into wc_test values(12,15,' ');

1 row created.

SCOTT-New rows> commit;

Commit complete.

SCOTT-New rows> update wc_test set y=99 where id=10;

1 row updated.

SCOTT-New rows>

Возвращаемся в сеанс "Blocker" и фиксируем транзакцию. В результате сеанс "Long update" продолжит выполнение команды update, обнаружит, что строка с id =5 теперь не удовлетворяет предикату и начнет выполнение команды update сначала, произведя "мини-откат". Но, как мы увидим, дойдя до заблокированной строки с id =10, он будет ждать завершения транзакции в сеансе "New rows":

SCOTT-Blocker> commit;

Commit complete.

SCOTT-Blocker>

Наконец, в сеансе "New rows": тоже зафиксируем транзакцию:

SCOTT-New rows> commit;

Commit complete.

SCOTT-New rows>

Теперь сеансу "Long update" никто не мешает завершить команду update:

Листинг 5

6 rows updated.

SCOTT-Long update> select id, y from wc_test;

        ID          Y
---------- ----------
         1         88
         2         88
         3         88
         4         88
         5         99
         6         16
         7         17
         8         18
         9         19
        10         99
        11         88
        12         88

12 rows selected.

SCOTT-Long update>

В результате мы видим, что сеанс "Long update" модифицировал строки с id =2,3,4, которые мы не изменяли во время тестов, строка с id =5 не изменена, хотя на момент начала выполнения update она удовлетворяла предикату. Кроме того, видно, что изменены строки с id =11 и 12, которых вообще не было на момент начала выполнения команды update в сеансе "Long update".

Теперь посмотрим, какую же информацию можно почерпнуть из трассировочного файла. Как я уже говорил, цвет текста трассировочного файла будет соответствовать цвету, которым выделено описание каждого события в начале статьи. Ключевые места будут выделяться желтым фоном, комментарии и пояснения к содержимому ключевых мест трассировочных файлов я буду писать с отступом, черным цветом сразу за комментируемым текстом. Напоминаю, что трассировочные файлы, которые представлены в Листингах 6 и 7, созданы сеансом "Long update", который запускался мной под Oracle 9.2.0.7. Обратите внимание на то, что и объем трассировочной информации, и ее содержимое у вас могут отличаться от полученных мной. Это зависит от многих факторов, в том числе от версии Oracle, установки некоторых параметров инициализации (например, TRANSACTION_AUDITING), установок режима SUPPLEMENTAL LOGGING и т.д.

Листинг 6

updaul mode is UPDATE NOT LOCKED snap oldsnap env: (scn: 0x0004.00f32abf  xid: 
0x0000.000.00000000  uba: 0x00000000.0000.00  statement num=0  parent xid: xid: 
0x0000.000.00000000  scn: 0x0000.00000000 0sch: scn: 0x0000.00000000) env: (scn: 
0x0000.00000000
xid: 0x0000.000.00000000  uba: 0x00000000.0000.00  statement num=0  parent xid: xid: 
0x0000.000.00000000  scn: 0x0000.00000000 0sch: scn: 0x0000.00000000)


Видим, что сеанс начал обновление еще не заблокированных строк с SCN=0x0004.00f32abf

updrow: kauupd table 0 00018545.02800012.1 code 0
updrow: kauupd table 0 00018545.02800012.2 code 0
updrow: kauupd table 0 00018545.02800013.0 code 0
updrow: kauupd table 0 00018545.02800013.1 code 1

Происходит обновление строк в таблице. 0x00018545=99653 - это OBJECT_ID таблицы 
 wc_test  в DBA_OBJECTS. table 0 - это номер таблицы в блоке данных. В нашем случае
 в блоке одна таблица. 02800012.1 и т.д. - это  dba  (Data Block Address) 
и номера изменяемых строк. Сравните это с HEX_DBA и ROW# в Листинге 1. Процесс обновления
 был заблокирован сеансом ″Blocker″ на строке с  id =3 
(строка 00018545.02800012.2). После фиксации не изменившей значения столбца  y  
транзакции в сеансе ″Blocker″ сеанс ″Long update″ продолжил работу.
 При модификации строки с  id =5 обнаружилось, что строка перестала удовлетворять 
предикату команды update ( code  1) и ...
uba: 0x00c01256.3c42.54
uba: 0x00c01256.3c42.53
uba: 0x00c01256.3c42.52

... ″Long update″ произвел откат всех изменений, что нам показало событие 10218. 
При этом, что интересно и вполне разумно, несмотря на то, что блокировки со всех ранее 
заблокированных строк сняты, ″Long update″ не ″разбудил″ другие сеансы, 
которые ждут заблокированных при выполнении фазы ″mode is UPDATE NOT LOCKED″ строк. 
В этом можно убедиться, например, попытавшись еще в одном сеансе в момент после 
блокирования ″Long update″ (соответствующий концу Листинга 2) выполнить 
обновление строки с  id =2 - этот сеанс будет заблокирован до окончания транзакции 
в сеансе ″Long update″.
updaul mode is LOCK snap oldsnap env: (scn: 0x0004.00f32ae9  xid: 0x0002.05f.0001658f  
uba: 0x00000000.0000.00  statement num=0  parent xid: xid: 0x0000.000.00000000  scn: 
0x0004.00f32ae9 0sch: scn: 0x0000.00000000) env: (scn: 0x0004.00f32abf  xid: 
0x0000.000.00000000
  uba: 0x00000000.0000.00  statement num=0  parent xid: xid: 0x0000.000.00000000  scn: 
0x0000.00000000 0sch: scn: 0x0000.00000000)

После отката всех изменений, которые сделала команда update, Oracle пытается
 заблокировать все строки, удовлетворяющие предикату. Обратите внимание, что SCN команды
 изменился (увеличился), т.е. команда update перезапускается как бы в новый момент времени, 
чтобы ″увидеть″  все произошедшие в таблице изменения удовлетворяющих 
предикату строк с момента своего предыдущего запуска.
updrow: kddlkr table 0 00018545.02800012.0 code 0
updrow: kddlkr table 0 00018545.02800012.1 code 0
updrow: kddlkr table 0 00018545.02800012.2 code 0
updrow: kddlkr table 0 00018545.02800013.0 code 0
updrow: kddlkr table 0 00018545.02800015.0 code 17
updrow: kddlkr table 0 00018545.02800015.1 code 0
updrow: kddlkr table 0 00018545.02800015.2 code 0
Теперь первая фаза команды update - фаза согласованного чтения - обнаружит, 
что строка с  id =1 тоже удовлетворяет условию команды update, что новые строки с  id =10,11 
и 12 - тоже, а строка c  id =5 - нет. Но строка с  id =10 (00018545.02800015.0) будет 
заблокирована командой update в ″New rows″, поэтому ″Long update″ продолжит 
работу только после фиксации изменений в ″New rows″. После этой фиксации ″Long 
update″ обнаруживает, что строка с  id =10 была изменена так, что перестала удовлетворять 
предикату (об этом свидетельствует  code   17 ), но, несмотря на это, 
продолжает производить поиск и блокировку всех удовлетворяющих предикату строк таблицы. 
После окончания просмотра всей таблицы проверяется, возникала ли хоть раз ситуация, 
когда  code  был >0 при попытке блокировки строк. Если это так, как и случилось в 
нашем случае, то...
updaul mode is LOCK snap oldsnap env: (scn: 0x0004.00f32af1  xid: 0x0002.05f.0001658f  
uba: 0x00c01256.3c42.5a  statement num=0  parent xid: xid: 0x0000.000.00000000  scn: 
0x0004.00f32af1 0sch: scn: 0x0000.00000000) env: (scn: 0x0004.00f32ae9  xid: 
0x0002.05f.0001658f
  uba: 0x00000000.0000.00  statement num=0  parent xid: xid: 0x0000.000.00000000  scn: 
0x0004.00f32ae9 0sch: scn: 0x0000.00000000)
Происходит снова попытка блокировки всех удовлетворяющих предикату строк с 
новым SCN. При этом блокировки с уже заблокированных на фазе ″mode is LOCK″ 
строк не снимаются, никаких изменений и никакой  redo- информации для таких строк 
не генерируется.  Обратите внимание, что идентификатор (XID) транзакции не изменяется. 
Такие попытки блокировок будут происходить либо до тех пор, пока все вызовы функции 
 kddlkr  не завершатся с  code 0 , либо до тех пор, пока число таких попыток 
не превысит 5000 (подробности см. далее в описании алгоритмов ″мини-откатов″).
updrow: kddlkr table 0 00018545.02800012.0 code 0
updrow: kddlkr table 0 00018545.02800012.1 code 0
updrow: kddlkr table 0 00018545.02800012.2 code 0
updrow: kddlkr table 0 00018545.02800013.0 code 0
updrow: kddlkr table 0 00018545.02800015.1 code 0
updrow: kddlkr table 0 00018545.02800015.2 code 0

И только тогда, когда все  code  при очередной попытке блокировки строк 
на фазе ″mode is LOCK″ будут равны нулю, происходит обновление всех ранее 
заблокированных строк на завершающей фазе ″mode is UPDATE ALL LOCKED″.
updaul mode is UPDATE ALL LOCKED snap oldsnap env: (scn: 0x0004.00f32af1  xid: 
0x0002.05f.0001658f  uba: 0x00c01256.3c42.5a  statement num=0  parent xid: xid: 
0x0000.000.00000000  scn: 0x0004.00f32af1 0sch: scn: 0x0000.00000000) env: (scn: 
0x0004.00f32ae9
xid: 0x0002.05f.0001658f  uba: 0x00000000.0000.00  statement num=0  parent xid: xid: 
0x0000.000.00000000  scn: 0x0004.00f32ae9 0sch: scn: 0x0000.00000000)
updrow: kauupd table 0 00018545.02800012.0 code 0
updrow: kauupd table 0 00018545.02800012.1 code 0
updrow: kauupd table 0 00018545.02800012.2 code 0
updrow: kauupd table 0 00018545.02800013.0 code 0
updrow: kauupd table 0 00018545.02800015.1 code 0
updrow: kauupd table 0 00018545.02800015.2 code 0

Теперь это обновление обязательно завершится успешно (разумеется, если не возникнет 
форс-мажорных обстоятельств в виде SHUTDOWN ABORT, доступа к данным через поврежденный 
индекс и т.д.), так как: 1) эта фаза выполняется с тем же SCN, что и последняя 
фаза ″mode is LOCK″. Что в свою очередь означает, что после выполнения 
согласованного чтения блоков таблицы  wc_test  на этой завершающей фазе мы получим 
тот же набор  строк, подлежащих изменению, что и на последней 
фазе ″mode is LOCK″. Кроме того, эти строки уже заблокированы нашей 
транзакцией на предыдущих шагах, что гарантирует их неизменность  с момента этой 
блокировки.

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 10.10.2008 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Oracle Database Personal Edition Named User Plus License
Oracle Database Personal Edition Named User Plus Software Update License & Support
Oracle Database Standard Edition 2 Named User Plus License
Oracle Database Standard Edition 2 Processor License
Stimulsoft Reports Server Team 10 users
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
СУБД Oracle "с нуля"
Компьютерные книги. Рецензии и отзывы
Windows и Office: новости и советы
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100