Поддержка согласованности в базе данных Oracle

Согласованность в базе данных Oracle при транзакцияхВ предыдущей статье мы рассмотрели работу механизма отмены UNDO в базе данных Oracle и его влияние на модификацию блоков данных. Мы продемонстрировали как изменяются во времени связи между элементами ITL и соответствующими частями undo-сегмента. А что происходит дальше? Oracle клонирует блок в памяти и выполняет массу работы, чтобы от текущей версии добраться до версии, которая выглядит так:

Itl           Xid                 Uba         Flag       Lck Scn/Fsc
0x01 0x0009.00d.00002100 0x018030ca.074c.11 C--- 0 scn 0x0000.01731c7a
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x12:pri[0] offs=0x1f68
0x14:pri[1] offs=0x1f71
0x16:pri[2] offs=0x1f85
tab 0, row 0, @0x1f68
tl: 9 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [ 2] c1 02
col 1: [ 2] c1 02
tab 0, row 1, @0x1f71
tl: 10 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [ 2] c1 03
col 1: [ 3] c2 02 03
tab 0, row 2, @0x1f85
tl: 9 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [ 2] c1 04
col 1: [ 2] c1 04

Обратите внимание, что элемент ITL с индексом 0x2 вновь вернулся в состояние «неиспользуемый», а элемент с индексом 0x1 ссылается на транзакцию с ID 0x0009.00d.00002100, а не 0x000a.00e.00001b93. Кроме того, эта транзакция отмечена как подтвержденная и очищенная (Flag = C---) и счетчик блокировок в ней сброшен в нуль. Это транзакция, подтвержденная в сеансе 2. Изменения, выполненные в сеансах 1 и 3 – которые еще не подтверждены – вообще недоступны из этой версии блока.

Взаимосвязь ITL с undo-сегментом

Рис. 1. Связи между элементом ITL и соответствующим undo-сегментом

Перейдем к данным: строки хранят значения (1,1), (2,102) и (3,3), и все три строки имеют нуль в байте блокировки (то есть, ни одна из строк не заблокирована). Однако, обратите внимание на адрес строки 0 в блоке: он снова изменился с 0x1f7b на 0x1f68. Реализация Oracle выполнила следующие действия:

  1. Скопировала блок в другой буфер, чтобы использовать копию для следующих операций.
  2. Выполнила очистку всех подтвержденных транзакций для этого блока.
  3. Отменила изменения, выполненные всеми неподтвержденными транзакциями.
  4. Если имеются какие-либо изменения, выполненные транзакцией с номером SCN подтверждения (commit SCN) выше номера SCN целевой транзакции (например, номер SCN, зафиксированный в момент начала выполнения запроса, инструкции DML или транзакции), выполняется отмена таких изменений.
  5. Шаг 4 повторяется при необходимости.

В данном случае потребовалось выполнить меньшее число шагов. Ниже снова приводится список ITL для текущей версии блока, до начала каких-либо операций, связанных с согласованным чтением:

Itl       Xid                 Uba             Flag Lck      Scn/Fsc
0x01 0x000a.00e.00001b93 0x01800518.04f5.34 --U- 1 fsc 0x0000.01731c83
0x02 0x0004.00c.00001964 0x018036ad.05ff.3a ---- 1 fsc 0x0000.00000000

На первом шаге Oracle выясняет (по состоянию в слоте 12, в таблице транзакций внутри заголовка undo-сегмента 4), что транзакция в элементе 0x02 списка ITL все еще активна. Соответственно, изменения, выполненные этой транзакцией в данном блоке, требуется отменить. Для этого Oracle обращается к блоку отмены 0x018036ad, определяет порядковый номер (инкарнации) 0x5ff, и затем находит запись 0x3a, которая сообщает, что «столбец 1 строки 0 в таблице 0 должен получить значение c1 02» (внутреннее представление десятичного числа 1). В результате этой операции длина строки должна измениться, поэтому Oracle копирует строку в свободное пространство внутри блока и выполняет необходимое изменение. Запись отмены также требует отметить элемент ITL как «неиспользуемый». Как результат, после отмены список ITL в копии выглядит так: 

Itl      Xid                     Uba         Flag Lck        Scn/Fsc
0x01 0x000a.00e.00001b93 0x01800518.04f5.34 --U- 1 fsc 0x0000.01731c83
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000

Больше неподтвержденных транзакций нет, поэтому далее Oracle проверяет, достигнут ли требуемый номер SCN, читая все SCN в списке ITL, и решает, что номер 0x01731c83, самый большой из имеющихся, слишком высок. По этой причине, Oracle запускает процесс отката изменений, выполненных в транзакции 0x000a.00e.00001b93, читая запись отмены 0x01800518.04f5.34. Эта запись сообщает, что столбец 1 строки 2 в таблице 0 должен получить значение c1 04 (десятичное число 3). Поскольку это не влияет на размер строки, Oracle выполняет изменение на месте. Запись отмены также сообщает, что это лишь первое из изменений в данном блоке, которое нужно откатить, и дополнительно нужно вернуть прежнюю версию элемента ITL. Как рассказывалось в этой статье, первое изменение, которое выполняет транзакция в блоке, является особым случаем, требующим выбрать список ITL и сохранить его содержимое (иногда все элементы текущего списка ITL оказываются задействованными, из-за чего транзакция бывает вынуждена создать новый – если достаточно места). В частности, запись отмены содержит некоторую информацию, ясно указывающую на элемент ITL, который выглядит так: 

op: L itl: xid: 0x0009.00d.00002100 uba: 0x018030ca.074c.11
                flg: C---      lkc: 0      scn: 0x0000.01731c7a

Далее Oracle копирует его на свое место и копия списка ITL приобретает следующий вид:

Itl         Xid                  Uba         Flag Lck        Scn/Fsc
0x01 0x0009.00d.00002100 0x018030ca.074c.11 C--- 0 scn 0x0000.01731c7a
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
 

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

Примечание. Когда Oracle обращается к строкам по индексам, он может воспользоваться механизмом RowCR (Row Consistent Read – согласованное чтение строк), когда уже имеет блок таблицы. Это означает, что описанная процедура была выполнена, чтобы получить листовой блок индекса в согласованном состоянии и проверить, что сама строка не изменялась после перестраивания номера SCN подтверждения для индекса.

Согласованность данных в СУБД Oracle при отмене транзакций

 

«Согласованная» не значит «существовавшая»

Следует отметить один интересный момент: версия блока, созданная выше, в действительности никогда не существовала. Мы получили блок, в котором отсутствуют изменения, выполненные в сеансе 1, но имеются изменения, выполненные в сеансе 2. Такое положение дел никогда не имело места в цепочке событий, произошедших на момент начала выполнения запроса.

Фактически эта версия самая близкая к тому, что имелось в момент, непосредственно предшествовавший началу изменений в сеансе 3. В тот момент список ITL для блока выглядел так:

Itl          Xid                 Uba         Flag Lck       Scn/Fsc
0x01 0x0009.00d.00002100 0x018030ca.074c.11 --U- 1 fsc 0x0000.01731c7a
0x02 0x0004.00c.00001964 0x018036ad.05ff.3a ---- 1 fsc 0x0000.00000000

Обратите сразу внимание, что элемент 0x01 сообщает о фиксирующей очистке (--U-, 1, fsc), хотя когда мы извлекали запись отмены для следующей транзакции, в этом элементе хранилось (C---,0,fsc). Этот пример демонстрирует работу отложенной очистки блоков данных (delayed logging block cleanout). Следующая транзакция не скопировала информацию, имевшуюся в элементе ITL, а сохранила информацию, которая была бы, если бы Oracle выполнил очистку в первый же момент.

Примечание. Существует распространенное (и вполне оправданное) мнение, что согласованное чтение возвращает блоки обратно «в прошлое». Но в действительности все гораздо сложнее, потому что иногда приходится иметь дело с целым комплексом подтвержденных и неподтвержденных транзакций, а также с побочными эффектами фиксирующей очистки. Вероятно, именно поэтому RAC различает состояния CR (consistent read – согласованное чтение) и PI (past image – старый образ). Состояние PI получают копии блока, являющиеся версиями блока, которые действительно существовали в прошлом и по этой причине могут использоваться как основа для отката, если экземпляр, хранящий их, завершится аварийно.

Есть некоторые тонкости, касающиеся этой темы, но мне кажется, что я дал достаточный объем информации и дампов блока, опираясь на которые вы сможете начать самостоятельные исследования. Следует также заметить, что ситуация осложняется (особенно в 10g) побочными эффектами, связанными с работой механизма «in-memory undo» и приватными буферами повторения, но эти сложности проявляются лишь в деталях и влияют только на момент, когда изменения действительно будут обнаруживаться в дампах блоков. Чтобы вам было проще следить за примерами, в процессе их создания я постоянно выполнял инструкции alter system checkpoint и alter system flush buffer_cache, чтобы всегда можно было получить последнюю версию измененного блока с диска и избежать некоторых частных случаев, возникающих из-за задержек; эти операции действительно влияют на порядок работы Oracle, но я не думаю, что эта разница существенна для описание основ.

Проделанная работа

Существует одна маленькая деталь, относящаяся к согласованному чтению, о которой следует упомянуть: как измерить объем проделанной работы. На этот случай имеется три важные статистики: 

CR blocks created
data blocks consistent reads - undo records applied
consistent gets - examination

Каждый раз, когда запускается процесс конструирования согласованной версии блока данных, происходит увеличение первой статистики; каждый раз, когда выполняется чтение записи отмены из блока отмены, увеличивается вторая статистика; и каждый раз, когда для этого извлекается блок отмены, на время его чтения приобретается и удерживается соответствующая защелка «cache buffers chains» – эта операция регистрируется в третьей статистике.

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

К сожалению, существуют и другие операции, которые требуют чтения блоков с применением той же стратегии приобретения и удержания защелки «cache buffers chains». К ним относятся некоторые операции доступа к блокам индексов, включая, например, индексно-организованные таблицы (Index Organized Tables, IOT) и хеш-кластеры одной таблицы, которые составляют две причины применения записей отмены (с третьей причиной мы познакомимся чуть ниже). Поэтому данные статистики не позволяют получить точную оценку объема работы, выполняемой при конструировании блоков во время согласованного чтения, хотя все еще остаются полезными.

Еще одной статистикой, имеющей отношение к обсуждаемой теме, является consistent changes. Она имеет тот же (или почти тот же) смысл, что и статистика data blocks consistent reads - undo records applied, но появилась в Oracle значительно раньше. Наконец, помните, что зачастую конструирование корректной версии блока вообще не требует выполнения какой-либо работы и многие операции согласованного чтения могут быть зафиксированы, как no work - consistent read gets.

Примечание. Статистики, имеющие отношение consistent gets, описывают объем работы, которую пришлось выполнить, чтобы получить «правильную версию» блока. К сожалению, они подвержены влиянию побочных эффектов. Базовая статистика, например, учитывает число восстановленных, а также число блоков отмены, которые потребовалось прочитать для восстановления. К счастью, число прочитанных блоков отмены также сохраняется в статистике consistent gets - examination, а число восстановленных блоков – в CR blocks created. Но, к сожалению, обе эти статистики, подвержены влиянию других операций.

Вас заинтересует / Intresting for you:

Транзакция базы данных Oracle
Транзакция базы данных Oracle 2475 просмотров Antoniy Tue, 21 Nov 2017, 13:18:46
Транзакции в Oracle
Транзакции в Oracle 18232 просмотров Ирина Светлова Tue, 21 Nov 2017, 13:18:05
Номер SCN подтверждения в базе...
Номер SCN подтверждения в базе... 6258 просмотров Игорь Воронов Tue, 21 Nov 2017, 13:17:28
Транзакции и механизм отмены U...
Транзакции и механизм отмены U... 5670 просмотров Игорь Воронов Tue, 21 Nov 2017, 13:17:28
Войдите чтобы комментировать