Уровни изоляции
Уровень изоляции — это степень, в которой транзакция в системе управления базами данных (СУБД) изолируется от других параллельно выполняющихся транзакций. Уровень изоляции определяет, какие аномалии данных (проблемы параллельного доступа) допустимы в данной транзакции, а какие — нет. Чем выше уровень изоляции, тем более корректными и предсказуемыми будут результаты, но тем ниже производительность системы из-за увеличения накладных расходов на синхронизацию.
История и стандартизация
Концепция уровней изоляции была формализована в 1992 году в стандарте SQL-92 (ANSI/ISO). До этого СУБД использовали различные механизмы блокировок, но единой терминологии не существовало. Стандарт SQL-92 определил четыре основных уровня изоляции, основанных на предотвращении трёх классических аномалий: «грязного чтения», «неповторяющегося чтения» и «фантомного чтения». Впоследствии, в 1995 году, исследователи Х. Беренсон, Ф. Бернштейн, Дж. Грей и другие в работе «A Critique of ANSI SQL Isolation Levels» расширили классификацию, добавив понятие «снапшот-изоляции» (snapshot isolation) и показав, что стандартные определения не охватывают всех возможных аномалий.
Классификация аномалий параллельного доступа
Для понимания уровней изоляции необходимо определить ключевые аномалии, которые могут возникать при одновременном выполнении нескольких транзакций:
- Грязное чтение (Dirty Read) — чтение данных, которые были изменены другой транзакцией, но ещё не зафиксированы (не подтверждены операцией COMMIT). Если эта другая транзакция впоследствии откатится (ROLLBACK), прочитанные данные окажутся недействительными.
- Неповторяющееся чтение (Non-Repeatable Read) — ситуация, при которой при повторном чтении одной и той же строки в рамках одной транзакции получается разный результат. Это происходит из-за того, что между двумя чтениями другая транзакция изменила и зафиксировала эту строку.
- Фантомное чтение (Phantom Read) — ситуация, при которой при повторном выполнении одного и того же запроса с условием (например,
SELECT * FROM users WHERE age > 30) в рамках одной транзакции возвращается разный набор строк. Это происходит из-за того, что другая транзакция между выполнениями запроса добавила или удалила строки, удовлетворяющие условию. - Потерянное обновление (Lost Update) — аномалия, при которой две транзакции одновременно читают одно и то же значение, затем каждая изменяет его, и последняя фиксация перезаписывает результат первой, не учитывая его. Стандарт SQL-92 не включал эту аномалию в определение уровней изоляции, но она часто рассматривается на практике.
Уровни изоляции по стандарту SQL-92
Стандарт SQL-92 определяет четыре уровня изоляции, которые обеспечивают защиту от перечисленных аномалий в разной степени. Уровни перечислены от самого низкого (наименее надёжного, но самого быстрого) к самому высокому (наиболее надёжному, но медленному).
Read Uncommitted (Чтение незафиксированных данных)
Самый низкий уровень изоляции. Транзакция может читать данные, изменённые другими параллельными транзакциями, даже если те ещё не зафиксированы. Это означает, что возможны «грязные чтения».
- Защита от аномалий: минимальная. Допускаются все три классические аномалии: грязное, неповторяющееся и фантомное чтение.
- Применение: используется крайне редко, в основном в системах, где скорость критичнее точности данных, и где допустимы временные несоответствия (например, при чтении приблизительной статистики, где точность до секунды не важна). На практике в большинстве современных СУБД (PostgreSQL, MySQL с InnoDB) этот уровень реализован так же, как Read Committed, поскольку «грязное чтение» технически сложно реализовать без серьёзных проблем с производительностью.
Read Committed (Чтение зафиксированных данных)
Наиболее распространённый уровень изоляции в большинстве СУБД. Транзакция видит только те данные, которые были зафиксированы на момент начала выполнения каждого отдельного оператора (запроса). Это предотвращает «грязное чтение», но не гарантирует повторяемости чтения.
- Защита от аномалий: предотвращает грязное чтение. Допускает неповторяющееся и фантомное чтение.
- Применение: стандартный уровень для большинства OLTP-систем (систем обработки транзакций в реальном времени), где важна актуальность данных на момент запроса, но не требуется строгая согласованность между несколькими запросами в одной транзакции. Например, в интернет-магазине при просмотре каталога товаров допустимо, что цена изменилась между двумя запросами страницы.
Repeatable Read (Повторяемость чтения)
Уровень изоляции, гарантирующий, что если транзакция прочитала строку, то при повторном чтении в рамках этой же транзакции она увидит те же самые значения. Это достигается блокировкой прочитанных строк или использованием механизма снимков данных (snapshot). Предотвращает грязное и неповторяющееся чтение.
- Защита от аномалий: предотвращает грязное и неповторяющееся чтение. Допускает фантомное чтение (хотя в некоторых СУБД, например, в PostgreSQL, этот уровень фактически предотвращает и фантомы за счёт снимков данных).
- Применение: используется в сценариях, где требуется, чтобы данные, прочитанные в начале транзакции, оставались неизменными до её завершения. Например, при формировании отчёта, где нужно просуммировать значения по строкам, и важно, чтобы сумма не изменилась из-за параллельных изменений.
Serializable (Сериализуемый)
Самый высокий уровень изоляции. Гарантирует, что результат параллельного выполнения набора транзакций эквивалентен результату их последовательного (одного за другим) выполнения в некотором порядке. Это полностью предотвращает все три классические аномалии, а также потерю обновлений и другие возможные аномалии.
- Защита от аномалий: полная. Предотвращает грязное, неповторяющееся и фантомное чтение, а также потерю обновлений.
- Реализация: достигается либо полным блокированием таблиц и диапазонов строк (блокировки предикатов), либо использованием оптимистичных методов (snapshot isolation с обнаружением конфликтов). Второй подход (например, в PostgreSQL и Microsoft SQL Server) называется «Serializable Snapshot Isolation» (SSI). Он позволяет избежать полного блокирования, но при обнаружении конфликта одна из транзакций принудительно откатывается.
- Применение: используется в системах, где требуется абсолютная согласованность данных, например, в финансовых приложениях (переводы между счетами, начисление процентов), системах бронирования (авиабилеты, гостиницы) и в других критически важных сценариях. Из-за высоких накладных расходов на синхронизацию и возможных откатов транзакций этот уровень значительно снижает пропускную способность системы.
Дополнительные уровни и механизмы
Помимо четырёх стандартных уровней, на практике используются и другие концепции:
Snapshot Isolation (Изоляция снимков)
Не является частью стандарта SQL-92, но широко реализована в современных СУБД (Oracle, PostgreSQL, Microsoft SQL Server, MySQL с InnoDB). При этом уровне каждая транзакция получает «снимок» базы данных на момент своего начала. Все последующие чтения в рамках этой транзакции видят данные из этого снимка, независимо от изменений, внесённых другими транзакциями. Это предотвращает грязное, неповторяющееся и фантомное чтение. Однако снимок-изоляция не гарантирует сериализуемости и может приводить к аномалиям, связанным с нарушением целостности данных (например, к аномалии «запись-зависимость» или «сиротские записи»). В PostgreSQL и SQL Server снимок-изоляция реализована как отдельный уровень, а не как замена Repeatable Read.
Serializable Snapshot Isolation (SSI)
Развитие снимок-изоляции, реализованное в PostgreSQL (начиная с версии 9.1) и Microsoft SQL Server. SSI добавляет обнаружение конфликтов между транзакциями, работающими со снимками. Если обнаруживается, что две транзакции могли бы в последовательном порядке привести к другому результату, одна из них откатывается. Это позволяет достичь полной сериализуемости без использования дорогостоящих блокировок диапазонов.
Выбор уровня изоляции
Выбор уровня изоляции является компромиссом между согласованностью данных и производительностью. Разработчик должен оценить, какие аномалии допустимы для конкретного приложения, и выбрать минимально необходимый уровень изоляции, чтобы избежать излишних накладных расходов.
- Read Uncommitted — практически не используется.
- Read Committed — стандартный выбор для большинства веб-приложений и OLTP-систем, где важна производительность, а временные несоответствия данных между запросами в одной транзакции допустимы.
- Repeatable Read — подходит для операций, требующих стабильности данных в рамках одной транзакции (например, отчёты, аналитика).
- Serializable — используется только в критически важных сценариях, где абсолютная согласованность данных важнее производительности.
Интересные факты
- В СУБД Oracle уровень изоляции по умолчанию — Read Committed, но он реализован через снимок-изоляцию, что на практике предотвращает неповторяющееся чтение, хотя формально не гарантирует его.
- В MySQL с движком InnoDB уровень по умолчанию — Repeatable Read, который в сочетании с механизмом блокировок диапазонов (gap locks) предотвращает фантомное чтение.
- В PostgreSQL уровень по умолчанию — Read Committed, но он также реализован через снимок-изоляцию, что даёт защиту от неповторяющегося чтения в рамках одного оператора, но не в рамках всей транзакции.
- Термин «грязное чтение» (dirty read) происходит от английского «dirty data» — данные, которые ещё не зафиксированы и могут быть откатаны, то есть «грязные».
Источники
- Стандарт ANSI/ISO SQL-92 (ISO/IEC 9075:1992).
- Berenson, H., Bernstein, P., Gray, J., Melton, J., O'Neil, E., & O'Neil, P. (1995). A Critique of ANSI SQL Isolation Levels. Proceedings of the 1995 ACM SIGMOD International Conference on Management of Data.
- Gray, J., & Reuter, A. (1993). Transaction Processing: Concepts and Techniques. Morgan Kaufmann.
- Документация PostgreSQL: Chapter 13. Concurrency Control.
- Документация MySQL: InnoDB Transaction Model and Locking.
- Документация Microsoft SQL Server: Transaction Isolation Levels.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →