Уровни изоляции транзакций Oracle и стандарт ISO

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

Стандарт ISO (http://www.iso.ch) о транзакциях основан на двух ключевых операторах завершения транзакции — COMMIT и ROLLBACK. Согласно стандарту ISO, все транзакции начинаются с оператора SELECT, UPDATE, INSERT или DELETE. Ни одна транзакция не может видеть промежуточных результатов других транзакций. Результаты второй транзакции доступны первой только после завершения второй.

Стандарты ISO о транзакциях гарантируют соответствие транзакций свойствам атомарности и изоляции, и помогают избежать проблем параллелизма, описанных в предыдущей статье о транзакциях Oracle. Все транзакции должны гарантировать сохранение согласованности базы данных. База данных находится в согласованном состоянии перед началом транзакции, и должна оставаться согласованной к ее концу.

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

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


Основные стадии обработки SQL и транзакции


Операторы SQL проходят несколько стадий своей обработки: разбор, связывание и выполнение. Для хранения разобранных операторов и прочей информации, связанной с текущими обрабатываемыми операторами, Oracle использует курсоры — приватные области SQL. Oracle автоматически открывает курсор для всех операторов SQL.

Разбор

На стадии разбора (синтаксического анализа) Oracle выполняет несколько действий по проверке операторов SQL.

  • Oracle проверяет синтаксическую корректность операторов. Сервер просматривает словарь данных, удостоверившись, что все спецификации таблиц и столбцов правильны.
  • Oracle проверяет наличие достаточных привилегий для выполнения запрошенных действий в операторах SQL.
  • Oracle разрабатывает план выполнения оператора, который включает выбор наилучших методов для достижения цели оператора.

После проверки привилегий Oracle назначает оператору SQL номер, именуемый хеш-значением SQL, в целях идентификации. Если это хеш-значение SQL уже присутствует в памяти, Oracle находит существующий план выполнения оператора, который, помимо прочего, детализирует наиболее оптимальный путь обращения к различным объектам базы данных. Если такой план существует, Oracle переходит непосредственно к выполнению оператора с использованием этого плана. Это называется частичным разбором (soft parse) и является предпочтительной техникой обработки операторов. Поскольку при этом используются ранее разработанные планы выполнения, частичный разбор является быстрым и эффективным.

Противоположностью частичному разбору является полный разбор (hard parse), и Oracle приходится прибегать к нему, если не удается найти в памяти хеш-значение SQL для оператора,который нужно выполнить. Полный разбор требует системной памяти и прочих ресурсов. Oracle должен создать свежий план выполнения, а это означает перебор множества возможностей и выбор наилучшей из всех. Во время этого процесса для проверки словаря данных Oracle требуется многократный доступ к библиотечному кэшу и кэшу словаря, и каждый раз при обращении к этим областям общего пользования Oracle должен устанавливать защелки (latch), которые представляют собой низкоуровневый механизм управления сериализацией и помогают защитить разделяемые структуры данных в SGA. Таким образом, полный разбор повышает конкуренцию в отношении защелок.

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

После завершения стадии разбора Oracle предоставляет для оператора разделяемую область SQL. Другие пользователи могут обращаться к этой разобранной версии до тех пор, пока она остается в памяти.

Связывание

На стадии связывания (binding) Oracle извлекает значения для переменных, использованных на стадии разбора. Обратите внимание, что эти переменные расширяются в литеральные значения только по завершении стадии разбора.

Выполнение

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

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


На заметку! Для вас, как администратора базы данных, важно полностью понимать природу транзакций в реляционной базе данных. Хорошее руководство на эту тему содержится в книге Джима Грея (Jim Gray), ведущего эксперта в базах данных и обработке транзакций, и Андреаса Рейтера (Andreas Reuter) под названием Transaction Processing: Concepts and Techniques (Morgan Kaufman, 1993 г.).


 

Уровни изоляции Oracle

Стандарты транзакций ISO используют понятие уровня изоляции для обозначения степени взаимодействия между транзакциями в базе данных. Изоляция определяет, как и когда изменения, проведенные операцией, становятся видимыми параллельным операциям в базе данных. Изоляция транзакций ограждает параллельно выполняющиеся транзакции от наблюдения незавершенных результатов других транзакций. Основными уровнями изоляции являются SERIALIZABLE (сериализуемый), REPEATABLE READ (повторяемое чтение), READ UNCOMMITTED (чтение только незафиксированных данных) и READ COMMITTED (чтение только зафиксированных данных). Вот что означает каждый из перечисленных уровней изоляции.

  • SERIALIZABLE (сериализуемый). На уровне изоляции SERIALIZABLE все транзакции полностью изолированы друг от друга, как если бы они выполнялись последовательно одна за другой. При уровне изоляции SERIALIZABLE транзакции, выполняющие вставку, удаление и обновление, помещают блокировку записи на набор данных, который они затрагивают в операции DML. База данных блокирует эти данные до тех пор, пока изолирующая транзакция не освобождает свои блокировки, что происходит при ее фиксации или откате. Поскольку другие транзакции,включающие операции DML, должны ожидать, пока блокировки не будут сняты, эти транзакции не смогут прочитать никаких грязных данных. Уровень изоляции SERIALIZABLE также помогает избегнуть невоспроизводимых чтений, потому что последующие транзакции не смогут обновлять или удалять заблокированные данные. Вы также избавляетесь от фантомных данных, поскольку последующие транзакции не могут вставить никаких новых строк, которые попадают в диапазон данных, заблокированных первой транзакцией.
  • REPEATABLE READ (повторяемое чтение). Уровень изоляции REPEATABLE READ гарантирует согласованность чтения — транзакция, которая дважды читает данные из таблицы в два разных момента времени, каждый раз увидит одни и те же значения. При этом уровне изоляции вы избегаете как проблемы грязного чтения, так и проблемы невоспроизводимого чтения.
  • READ UNCOMMITTED (чтение только незафиксированных данных). Уровень READ UNCOMMITTED, который позволяет транзакции читать промежуточные данные другой транзакции перед тем, как она их зафиксирует, приведет к проявлению всех проблем параллельного использования.
  • READ COMMITTED (чтение только зафиксированных данных). Уровнем изоляции Oracle по умолчанию является READ COMMITTED на уровне оператора. Запросы Oracle видят данные, которые были зафиксированы на момент начала запроса. Поскольку уровень изоляции действует на уровне оператора, каждый оператор может видеть только те данные, которые были зафиксированы перед началом выполнения этого оператора. Уровень изоляции READ COMMITTED гарантирует, что данные строки не изменятся, пока вы обращаетесь к определенной строке в таблице Oracle.

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


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

Три из четырех главных уровней изоляции ISO позволяют совершить некоторое отступление от теоретической концепции сериализуемых транзакций. В таблице ниже  показано, до каких пределов каждый из четырех уровней изоляции страдает от проблем параллелизма, перечисленных ранее. Обратите внимание, что значение “Да” в таблице означает, что определенная проблема возможна при данном уровне изоляции, а значение “Нет” — что проблема на данном уровне изоляции невозможна.

Уровень изоляции Грязное чтение Невоспроизводимое чтение Фантомное чтение
READ UNCOMMITTED Да Да Да
READ COMMITTED Нет Да Да
REPEATABLE READ Нет Нет Да
SERIALIZABLE Нет Нет Нет

Как видите, последний уровень изоляции в табл. 8.1 — SERIALIZABLE — позволяет избежать всех проблем параллелизма, но к сожалению, является не слишком применимым практически, поскольку не допускает никакого параллельного использования базы данных. Уровень изоляции Oracle по умолчанию — READ COMMITTED — избавляет от проблем грязного чтения и потерянных обновлений. Вы не сталкиваетесь с проблемой грязного чтения, поскольку запросы читают лишь те данные, которые были зафиксированы на момент начала запроса, что исключает чтение данных, которые могут быть позднее отменены другой транзакцией. Вдобавок вы избавлены от проблемы потерянных обновлений, поскольку транзакции не могут читать данные, которые модифицируются в данный момент, до тех пор, пока обновления не будут завершены.

 

Согласованность на уровне транзакции и на уровне оператора SQL

По умолчанию Oracle автоматически обеспечивает согласованность чтения на уровне оператора. То есть все данные, которые видит запрос, относятся к одному моменту времени. Это значит, что запрос видит согласованные данные на момент своего начала. Он видит только те данные, что были зафиксированы на момент его запуска, но никакие данные, зафиксированные в процессе его выполнения, ему не видны. Запросы в этом контексте не обязательно должны быть ограничены операторами SELECT. Оператор INSERT с подзапросом, UPDATE или DELETE также включают в себя неявный запрос и возвращают согласованные данные.

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

 

Изменение уровня изоляции по умолчанию

Уровень изоляции READ COMMITTED обеспечивает защиту от грязных чтений и потерянных обновлений, потому что запрашивает данные только после выполнения оператора COMMIT. Все транзакции согласованы на пооператорной основе. Читатели не блокируют транзакций-писателей и наоборот. Как видите, уровень изоляции READ COMMITTED, принятый в Oracle по умолчанию, не гарантирует того, что вы избежите проблем невоспроизводимого и фантомного чтения. Oracle гарантирует согласованность чтения только на уровне оператора, а не транзакции. Однако Oracle позволяет явно изменять стандартный уровень изоляции READ COMMITTED, устанавливая в качестве альтернативы уровень изоляции SERIALIZABLE.


На заметку! Уровень изоляции READ COMMITTED обеспечивает отличный параллелизм и согласованность базы данных. Однако этот режим не обеспечивает согласованности на уровне транзакции. Поскольку это изоляция на уровне оператора, изменения, проведенные между операторами и транзакцией, могут быть не видимыми запросу, и по этой причине проблема невоспроизводимого чтения остается в силе; вам просто не гарантируется получение того же результата при повторном выполнении запроса. Проблема фантомного чтения также присутствует, потому что модель не мешает другим транзакциям обновлять таблицы между вашими запросами.


Уровень изоляции SERIALIZABLE трактует базу данных как однопользовательскую, исключая все аномалии данных, вызванные параллельным использованием и модификацией данных. С помощью оператора ALTER SESSION можно установить уровень изоляции SERIALIZABLE и исключить проблемы параллелизма. Изменение уровня изоляции с принятого по умолчанию (READ COMMITTED) на уровень SERIALIZABLE производится следующим образом: 

SQL> ALTER SESSION SET ISOLATION LEVEL SERIALIZABLE;

Этот оператор обеспечит защиту всех транзакций, как зафиксированных, так и незафиксированных, которые произошли с момента начала транзакции. Вместо применения уровня изоляции SERIALIZABLE можно также воспользоваться командой SET TRANSACTION READ ONLY для обеспечения воспроизводимого чтения без чтения фантомного. Уровень изоляции SERIALIZABLE подходит для баз данных, в которых множество согласованных запросов выполняются на протяжении транзакции обновления. Однако сериализация — не простой выбор, потому что существенно сокращает уровень параллелизма. С установкой уровня изоляции SERIALIZABLE связаны проблемы, которые перечислены ниже.

  • Поскольку сериализация включает блокировку данных для монопольного пользования транзакциями, она снижает параллелизм транзакций.
  • Во время создания таблиц параметр INITTRANS должен быть установлен, по крайней мере, равным 3, чтобы уровень изоляции SERIALIZABLE возымел эффект. Параметр INITTRANS определяет количество параллельных транзакций на таблице.
  • Пропускная способность при уровне изоляции SERIALIZABLE намного ниже, чем при уровне READ COMMITTED, особенно в высоконагруженных базах данных со многими транзакциями, обращающими к одним и тем же таблицам с целью их обновления.
  • Если планируется использовать режим изоляции SERIALIZABLE, в приложении потребуется предусмотреть код проверки ошибок.
  • Сериализуемые транзакции более подвержены взаимоблокировкам — ситуациям,когда транзакции “застревают” в ожидании, пока каждая из них освободит блокировки объектов данных. Взаимоблокировки приводят к дорогостоящим откатам транзакций.

В общем случае безопаснее всего положиться на принятый в Oracle по умолчанию режим изоляции транзакций READ COMMITTED, который обеспечивает максимальную пропускную способность при совсем небольшом риске аномалий невоспроизводимых и фантомных чтений.

Уровень изоляции READ COMMITTED обеспечивает хороший компромисс между параллельным доступом к данным и их согласованностью. К тому же пропускная способность в этом режиме намного выше, чем в режиме SERIALIZABLE. Если получение воспроизводимого чтения — основной мотив для применения уровня изоляции SERIALIZABLE, всегда можно использовать явные блокировки в ситуациях, когда это необходимо.

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

 

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

Oracle Personal Edition
Oracle Personal Edition 5963 просмотров Надин Tue, 21 Nov 2017, 13:32:12
Oracle alerts: генерируемые се...
Oracle alerts: генерируемые се... 7217 просмотров Алексей Вятский Tue, 21 Nov 2017, 13:18:05
Установка Oracle 11g на Linux
Установка Oracle 11g на Linux 22904 просмотров Илья Дергунов Tue, 21 Nov 2017, 13:18:05
Дискретные и автономные транза...
Дискретные и автономные транза... 9269 просмотров Дэн Tue, 25 Sep 2018, 04:21:26
Войдите чтобы комментировать

anders7777 аватар
anders7777 ответил в теме #10451 2 года 1 мес. назад
Очень хорошее, понятное описание уровней изоляции транзакций.