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

Уровень изолированности Read Uncommitted

Read Uncommitted (чтение незафиксированных данных) — самый низкий уровень изолированности транзакций в системах управления базами данных (СУБД), при котором одна транзакция может читать данные, изменённые другой параллельной транзакцией, даже если эти изменения ещё не были зафиксированы (committed). Данный уровень обеспечивает максимальную производительность за счёт минимальных блокировок, но при этом допускает ряд аномалий, связанных с целостностью данных.

История и происхождение

Понятие уровней изолированности транзакций было формализовано в 1992 году в стандарте SQL-92 (ISO/IEC 9075:1992). Read Uncommitted был определён как первый из четырёх уровней в порядке возрастания строгости: Read Uncommitted, Read Committed, Repeatable Read и Serializable. Стандарт SQL-92 ввёл эту классификацию для унификации поведения СУБД при параллельном доступе к данным.

До появления стандарта различные СУБД реализовывали изолированность по-своему. Например, в ранних версиях Oracle (до 7.0) фактически не было уровней изолированности — все транзакции работали как Read Committed. В то же время в Informix и некоторых других системах по умолчанию использовался режим, близкий к Read Uncommitted, что приводило к частым аномалиям.

Принцип работы

Read Uncommitted реализуется путём минимального использования блокировок. В большинстве СУБД при этом уровне транзакция не устанавливает блокировки на читаемые данные (или устанавливает блокировки только на запись). Это позволяет другим транзакциям одновременно изменять те же строки, не дожидаясь завершения чтения.

Основные механизмы реализации:

  • Отсутствие блокировок на чтение — транзакция читает данные без захвата блокировок, что позволяет другим транзакциям изменять их.
  • Блокировки на запись — при изменении данных транзакция устанавливает блокировку, предотвращая одновременную запись другими транзакциями, но не блокирует чтение.
  • Грязное чтение (dirty read) — ключевая особенность: транзакция может прочитать данные, которые впоследствии будут отменены (откат транзакции), что приводит к потенциальной неконсистентности.

Аномалии, допускаемые уровнем

Read Uncommitted допускает все три основные аномалии параллельного доступа, определённые в стандарте SQL:

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

Транзакция A читает данные, изменённые транзакцией B, но ещё не зафиксированные. Если транзакция B впоследствии откатывается (ROLLBACK), прочитанные данные оказываются недействительными. Пример: транзакция A читает баланс счёта, который транзакция B увеличила на 1000 рублей, но B откатывается — A получает некорректные данные.

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

Одна и та же строка, прочитанная дважды в рамках одной транзакции, может дать разные результаты. Это происходит, если между двумя чтениями другая транзакция изменяет и фиксирует эту строку. Хотя на уровне Read Uncommitted это возможно, данная аномалия более характерна для Read Committed.

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

При повторном выполнении запроса с тем же условием (например, WHERE balance > 1000) набор строк может измениться: появиться новые строки (вставленные другой транзакцией) или исчезнуть старые (удалённые). Это также допустимо на уровне Read Uncommitted.

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

Не все СУБД поддерживают Read Uncommitted одинаково, а некоторые вообще не реализуют его.

PostgreSQL

PostgreSQL не поддерживает Read Uncommitted. При попытке установить этот уровень он автоматически повышается до Read Committed. Разработчики PostgreSQL аргументируют это тем, что реализация грязного чтения потребовала бы отказа от механизма многоверсионного управления (MVCC) в пользу блокировок, что снизило бы производительность и усложнило архитектуру.

MySQL (InnoDB)

MySQL с движком InnoDB поддерживает Read Uncommitted. При этом уровне InnoDB позволяет грязное чтение, но использует механизм версий для строк — транзакция может читать последнюю версию строки, даже если она ещё не зафиксирована. Это может приводить к неконсистентности, но производительность возрастает за счёт снижения блокировок.

Microsoft SQL Server

SQL Server полностью поддерживает Read Uncommitted. При установке этого уровня все запросы SELECT выполняются без блокировок, игнорируя любые блокировки, установленные другими транзакциями. Это эквивалентно использованию подсказки NOLOCK в запросах.

Oracle

Oracle не поддерживает Read Uncommitted. Как и PostgreSQL, при попытке установить этот уровень Oracle автоматически переключается на Read Committed. Это связано с архитектурой MVCC, где чтение никогда не блокирует запись, но грязное чтение невозможно.

SQLite

SQLite не поддерживает Read Uncommitted в стандартном режиме. Однако есть возможность включить режим «грязного чтения» через прагму PRAGMA read_uncommitted=1, но это работает только в определённых конфигурациях (например, при использовании отложенных транзакций).

Применение

Read Uncommitted используется в сценариях, где:

  • Требуется максимальная производительность — например, в системах реального времени, где скорость чтения критичнее точности данных.
  • Допустима некоторая неточность — в аналитических отчётах, где небольшие расхождения в данных несущественны (например, приблизительные статистические данные).
  • Чтение данных, которые не изменяются — если известно, что в момент чтения никакие другие транзакции не модифицируют данные, уровень безопасен.
  • Мониторинг и логирование — при сборе метрик, где допустимо чтение незафиксированных данных, так как они всё равно будут обработаны позже.

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

Read Uncommitted подвергается критике за потенциальную небезопасность. Основные претензии:

  • Нарушение целостности данных — грязное чтение может привести к тому, что приложение использует несуществующие данные, что в финансовых системах может вызвать ошибки.
  • Непредсказуемость — результаты запросов могут меняться от выполнения к выполнению, что усложняет отладку и тестирование.
  • Отсутствие поддержки в некоторых СУБД — PostgreSQL и Oracle не реализуют этот уровень, что ограничивает его применение в кроссплатформенных проектах.

Многие разработчики рекомендуют использовать Read Uncommitted только в крайних случаях, когда производительность критически важна, а точность данных не требуется. В большинстве приложений предпочтительнее Read Committed, который обеспечивает разумный баланс между производительностью и консистентностью.

Интересные факты

  • В стандарте SQL:1999 Read Uncommitted был переименован в READ UNCOMMITTED (все заглавные), но в SQL-92 использовалось написание с заглавных букв.
  • Некоторые СУБД (например, Firebird) не поддерживают Read Uncommitted, но предлагают альтернативные механизмы для повышения производительности, такие как «читающие транзакции» с низким уровнем изоляции.
  • В Microsoft SQL Server использование Read Uncommitted (или подсказки NOLOCK) может привести к ошибкам при чтении страниц данных, которые находятся в процессе реорганизации — это может вызвать исключения «неверный формат данных» (data corruption).

Источники

  • ISO/IEC 9075:1992 (SQL-92) — стандарт, определяющий уровни изолированности.
  • Документация PostgreSQL: «Transaction Isolation» — описание уровней изолированности.
  • Документация MySQL: «InnoDB Transaction Isolation Levels» — реализация Read Uncommitted в InnoDB.
  • Документация Microsoft SQL Server: «SET TRANSACTION ISOLATION LEVEL» — описание уровней изолированности.
  • Книга «SQL and Relational Theory: How to Write Accurate SQL Code» (C. J. Date) — обсуждение аномалий транзакций.
  • Статья «A Critique of ANSI SQL Isolation Levels» (H. Berenson et al., 1995) — критический анализ стандарта SQL-92.

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

На главную BFOmetr →