Открыть сервис

Уровни изоляции транзакций

Уровень изоляции транзакций — это мера, определяющая степень, в которой изменения, сделанные в рамках одной транзакции базы данных, становятся видимыми для других параллельно выполняющихся транзакций. Уровень изоляции является одним из четырёх основных свойств транзакций (ACID), наряду с атомарностью, согласованностью и долговечностью, и предназначен для баланса между производительностью системы и гарантиями целостности данных. Стандарт SQL-92 определяет четыре классических уровня изоляции, каждый из которых решает определённые аномалии параллельного доступа.

История и стандартизация

Понятие изоляции транзакций возникло в 1970-х годах с развитием реляционных баз данных, когда потребовалось обеспечить корректную работу нескольких пользователей с общими данными. В 1992 году Американский национальный институт стандартов (ANSI) и Международная организация по стандартизации (ISO) опубликовали стандарт SQL-92, который впервые формально определил четыре уровня изоляции и три основных типа аномалий. Этот стандарт лёг в основу большинства современных систем управления базами данных (СУБД), хотя многие из них (например, PostgreSQL, MySQL, Microsoft SQL Server, Oracle Database) реализуют его с собственными расширениями и нюансами.

Аномалии параллельного доступа

Для понимания уровней изоляции необходимо знать, какие проблемы могут возникать при одновременном выполнении транзакций. Стандарт SQL-92 выделяет три классические аномалии, хотя в реальных системах встречаются и другие.

Грязное чтение (Dirty Read)

Грязное чтение возникает, когда одна транзакция читает данные, изменённые другой транзакцией, которая ещё не была зафиксирована (не выполнила COMMIT). Если впоследствии эта вторая транзакция будет отменена (выполнит ROLLBACK), то первая транзакция окажется основанной на несуществующих данных. Например, транзакция A переводит деньги со счёта, уменьшая баланс, но не завершает операцию. Транзакция B читает уменьшенный баланс и принимает решение на основе этих данных. Если транзакция A откатывается, баланс восстанавливается, а транзакция B остаётся с некорректной информацией.

Неповторяющееся чтение (Non-Repeatable Read)

Неповторяющееся чтение происходит, когда одна транзакция дважды читает одни и те же данные в рамках своего выполнения, но между этими чтениями другая транзакция изменяет и фиксирует эти данные. В результате первая транзакция получает разные значения при первом и втором чтении. Например, транзакция A читает баланс счёта, затем транзакция B изменяет этот баланс и фиксирует изменение, после чего транзакция A снова читает баланс и видит уже другое значение.

Фантомное чтение (Phantom Read)

Фантомное чтение — это более сложная аномалия, связанная с добавлением или удалением строк, удовлетворяющих условию запроса. В отличие от неповторяющегося чтения, где меняется значение уже существующей строки, при фантомном чтении меняется сам набор строк. Например, транзакция A выполняет запрос «SELECT * FROM employees WHERE department = 'IT'» и получает 10 строк. Затем транзакция B вставляет новую запись о сотруднике в отдел IT и фиксирует изменение. При повторном выполнении того же запроса транзакция A получает уже 11 строк — «фантомная» строка появляется из ниоткуда.

Дополнительные аномалии

Некоторые СУБД и исследователи выделяют и другие аномалии, такие как потерянное обновление (Lost Update), когда две транзакции одновременно читают одни и те же данные, а затем каждая записывает своё изменение, и последняя запись перезаписывает первую, не учитывая её. Также существует аномалия сериализации (Serialization Anomaly), при которой результат параллельного выполнения транзакций не соответствует ни одному из возможных последовательных порядков их выполнения.

Четыре уровня изоляции по стандарту SQL-92

Стандарт SQL-92 определяет четыре уровня изоляции, которые различаются тем, какие аномалии они допускают. Уровни перечислены от самого слабого к самому строгому.

READ UNCOMMITTED (Чтение незафиксированных данных)

Это самый низкий уровень изоляции. Транзакция может читать данные, изменённые другими транзакциями, даже если те ещё не зафиксированы. На этом уровне допускаются все три классические аномалии: грязное чтение, неповторяющееся чтение и фантомное чтение. READ UNCOMMITTED используется крайне редко, так как он практически не гарантирует целостности данных. Его применение оправдано только в ситуациях, где точность данных не критична, а максимальная производительность важнее, например, при чтении приблизительных статистических данных или в системах с очень низкими требованиями к согласованности. В некоторых СУБД, таких как PostgreSQL, этот уровень не поддерживается и фактически эквивалентен READ COMMITTED.

READ COMMITTED (Чтение зафиксированных данных)

Этот уровень гарантирует, что транзакция читает только те данные, которые были зафиксированы (COMMIT) другими транзакциями. Грязное чтение предотвращается: незафиксированные изменения других транзакций не видны. Однако неповторяющееся чтение и фантомное чтение возможны, так как между двумя чтениями в рамках одной транзакции другие транзакции могут зафиксировать изменения. READ COMMITTED является уровнем изоляции по умолчанию в большинстве популярных СУБД, включая PostgreSQL, Oracle Database, Microsoft SQL Server (по умолчанию) и MySQL (с движком InnoDB). Он обеспечивает хороший баланс между производительностью и защитой от наиболее грубой аномалии — грязного чтения.

REPEATABLE READ (Повторяемое чтение)

На этом уровне гарантируется, что если транзакция прочитала строку, то при повторном чтении той же строки в рамках той же транзакции она увидит то же самое значение. Это достигается блокировкой прочитанных строк или использованием механизма многоверсионности (MVCC). Неповторяющееся чтение предотвращается, но фантомное чтение остаётся возможным, так как блокировки обычно не распространяются на диапазоны строк, и другие транзакции могут вставлять новые строки, удовлетворяющие условию запроса. REPEATABLE READ является уровнем по умолчанию в MySQL (с движком InnoDB) и в некоторых других СУБД. В PostgreSQL этот уровень также реализован, но он дополнительно предотвращает и фантомное чтение, что делает его более строгим, чем требует стандарт.

SERIALIZABLE (Сериализуемый)

Это самый строгий уровень изоляции. Он гарантирует, что результат параллельного выполнения транзакций эквивалентен результату их последовательного (одна за другой) выполнения в некотором порядке. На этом уровне предотвращаются все три классические аномалии: грязное чтение, неповторяющееся чтение и фантомное чтение. SERIALIZABLE достигается либо полной блокировкой всех данных, к которым обращается транзакция, либо использованием оптимистичных методов, таких как проверка конфликтов на этапе фиксации (serializable snapshot isolation). Этот уровень обеспечивает максимальную целостность данных, но ценой значительного снижения производительности из-за частых блокировок и откатов транзакций. SERIALIZABLE применяется в критических системах, где точность данных абсолютно необходима, например, в финансовых операциях или системах бронирования.

Реализация уровней изоляции в различных СУБД

Хотя стандарт SQL-92 определяет четыре уровня, реальные СУБД могут реализовывать их по-разному, используя различные механизмы, такие как блокировки (pessimistic locking) и многоверсионность (MVCC).

Блокировки (Locking)

При использовании блокировок СУБД блокирует строки, страницы или таблицы при чтении или записи, чтобы предотвратить конфликты. Блокировки могут быть разделяемыми (shared locks, для чтения) и исключительными (exclusive locks, для записи). Этот подход прост в реализации, но может приводить к взаимным блокировкам (deadlocks) и снижению параллелизма.

Многоверсионность (MVCC)

MVCC (Multi-Version Concurrency Control) — более современный и распространённый подход. Вместо блокировки данных СУБД хранит несколько версий одной строки. Каждая транзакция видит «снимок» данных на момент её начала (или на момент первого запроса, в зависимости от реализации). Это позволяет читателям не блокировать писателей и наоборот, что значительно повышает производительность. MVCC используется в PostgreSQL, Oracle, MySQL (InnoDB), Microsoft SQL Server (с версии 2005) и многих других.

Примеры реализации

  • PostgreSQL: Уровень по умолчанию — READ COMMITTED. REPEATABLE READ и SERIALIZABLE реализованы через MVCC и дополнительно предотвращают фантомное чтение и аномалии сериализации (в SERIALIZABLE с помощью проверки конфликтов).
  • MySQL (InnoDB): Уровень по умолчанию — REPEATABLE READ. READ COMMITTED также доступен. SERIALIZABLE реализуется через блокировки диапазонов (gap locks).
  • Oracle Database: Поддерживает только READ COMMITTED (по умолчанию) и SERIALIZABLE. READ UNCOMMITTED и REPEATABLE READ отсутствуют, так как в архитектуре Oracle они не имеют смысла.
  • Microsoft SQL Server: Уровень по умолчанию — READ COMMITTED. Поддерживаются все четыре уровня, а также дополнительный уровень SNAPSHOT, который похож на REPEATABLE READ, но использует версионирование строк.

Выбор уровня изоляции

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

  • Требования к целостности данных: Для финансовых или критических систем предпочтительны SERIALIZABLE или REPEATABLE READ.
  • Производительность: Слабые уровни (READ UNCOMMITTED, READ COMMITTED) обеспечивают более высокую пропускную способность, так как реже блокируют данные.
  • Частота конфликтов: В системах с высокой конкуренцией за одни и те же данные (например, биржевые торги) строгие уровни могут приводить к частым откатам транзакций, что снижает производительность.
  • Тип операций: Для отчётов и аналитики, где точность не критична, может быть достаточно READ COMMITTED. Для операций, требующих согласованного чтения (например, суммирование балансов), нужен REPEATABLE READ или SERIALIZABLE.

Критика и ограничения

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

Источники

  • ISO/IEC 9075:1992 (SQL-92) — стандарт, определяющий уровни изоляции и аномалии.
  • Gray, J., & Reuter, A. (1993). Transaction Processing: Concepts and Techniques. Morgan Kaufmann.
  • Bernstein, P. A., Hadzilacos, V., & Goodman, N. (1987). Concurrency Control and Recovery in Database Systems. Addison-Wesley.
  • Документация СУБД: PostgreSQL, MySQL, Oracle Database, Microsoft SQL Server.
  • Статья «A Critique of ANSI SQL Isolation Levels» (Berenson, H., et al., 1995) — критический анализ стандарта.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →