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

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

Чтение незафиксированных данных (англ. dirty read) — это феномен в системах управления базами данных (СУБД), при котором одна транзакция считывает данные, изменённые, но ещё не зафиксированные другой транзакцией. Если впоследствии изменяющая транзакция будет отменена (выполнит откат, или rollback), считанные данные окажутся некорректными, что может привести к нарушению целостности информации и логическим ошибкам в работе приложения.

Сущность явления

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

Пример

Предположим, существует таблица «Счета» с полем «Баланс». Транзакция A начинает списание 1000 рублей со счёта клиента, уменьшая баланс с 5000 до 4000 рублей, но ещё не завершает операцию (не фиксирует изменения). В этот момент транзакция B считывает значение баланса — 4000 рублей. Если затем транзакция A отменяется (например, из-за ошибки), баланс возвращается к исходному значению 5000 рублей. Однако транзакция B уже использовала неверные данные 4000 рублей, что может привести к неверным расчётам или решениям.

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

Возможность возникновения чтения незафиксированных данных напрямую зависит от уровня изоляции транзакций, определённого в стандарте SQL (ISO/IEC 9075). Стандарт выделяет четыре уровня изоляции, каждый из которых предотвращает определённые аномалии:

  1. Read Uncommitted (чтение незафиксированных данных) — самый низкий уровень изоляции. Транзакция может читать данные, изменённые, но не зафиксированные другими транзакциями. На этом уровне чтение незафиксированных данных разрешено, что делает его наиболее производительным, но наименее надёжным.
  2. Read Committed (чтение зафиксированных данных) — уровень, при котором транзакция видит только те данные, которые были зафиксированы другими транзакциями. Чтение незафиксированных данных предотвращается. Это наиболее распространённый уровень изоляции по умолчанию во многих СУБД, например, в PostgreSQL, Oracle Database и Microsoft SQL Server.
  3. Repeatable Read (повторяемое чтение) — гарантирует, что если транзакция повторно считывает одни и те же данные, она получит тот же результат, при условии, что данные не были изменены самой транзакцией. Предотвращает как чтение незафиксированных данных, так и неповторяющееся чтение.
  4. Serializable (сериализуемый) — самый высокий уровень изоляции. Транзакции выполняются так, как если бы они были последовательными (одна за другой), что полностью исключает все три аномалии, включая чтение незафиксированных данных.

Механизмы предотвращения

Для предотвращения чтения незафиксированных данных СУБД используют различные механизмы блокировок и управления версиями строк:

  • Блокировки (Locks): При изменении данных транзакция устанавливает исключительную блокировку на строки или страницы. Другие транзакции, пытающиеся прочитать эти данные на уровне изоляции «Read Committed» или выше, блокируются до завершения изменяющей транзакции. Этот подход может снижать производительность из-за ожидания освобождения блокировок.
  • Многоверсионное управление параллельным доступом (MVCCMulti-Version Concurrency Control): СУБД хранит несколько версий одной строки данных. Когда транзакция изменяет строку, создаётся новая версия, а старая сохраняется. Читающие транзакции видят «снимок» данных на момент начала своего выполнения (или на момент последнего зафиксированного состояния, в зависимости от реализации). Таким образом, они не блокируются и не видят незафиксированных изменений. MVCC используется в PostgreSQL, Oracle, MySQL (InnoDB) и других современных СУБД.

Последствия и риски

Использование уровня изоляции «Read Uncommitted» или недостаточная защита от чтения незафиксированных данных могут привести к серьёзным проблемам:

  • Нарушение целостности данных: Приложение может принять решение на основе неверных, впоследствии отменённых данных. Например, в банковской системе это может привести к двойному списанию или ошибочному начислению процентов.
  • Логические ошибки: В отчётах или аналитике могут появиться «грязные» данные, которые не соответствуют реальному состоянию системы.
  • Сложность отладки: Ошибки, вызванные чтением незафиксированных данных, часто являются трудно воспроизводимыми, так как зависят от временных условий выполнения параллельных транзакций.

Применение на практике

Несмотря на риски, уровень изоляции «Read Uncommitted» (или его эквиваленты, например, «READ UNCOMMITTED» в SQL Server или «NOLOCK» в подсказках запросов) иногда используется в системах, где скорость чтения критически важна, а точность данных не является строгим требованием. К таким сценариям относятся:

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

Однако в большинстве критически важных приложений (финансовые системы, системы управления заказами, медицинские информационные системы) использование «Read Uncommitted» считается недопустимым, и применяются уровни изоляции «Read Committed» или выше.

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

  • В стандарте SQL термин «dirty read» (грязное чтение) используется как для обозначения аномалии, так и для названия уровня изоляции, который её допускает.
  • Некоторые СУБД, такие как PostgreSQL, не реализуют уровень изоляции «Read Uncommitted» в его классическом виде. Вместо этого он ведёт себя как «Read Committed», так как архитектура MVCC в PostgreSQL не позволяет читать незафиксированные данные без специальных, нестандартных действий.
  • Понятие «чтение незафиксированных данных» является фундаментальным в теории транзакций и было формализовано в работах Джима Грея и других исследователей в области баз данных.

Источники

  • ISO/IEC 9075-2:2016, Information technology — Database languages — SQL — Part 2: Foundation (SQL/Foundation).
  • Gray, J., & Reuter, A. (1993). Transaction Processing: Concepts and Techniques. Morgan Kaufmann.
  • Date, C. J. (2003). An Introduction to Database Systems (8th ed.). Addison-Wesley.
  • Документация PostgreSQL, глава «Уровни изоляции транзакций».
  • Документация Microsoft SQL Server, глава «Уровни изоляции (ядро СУБД)».

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

На главную BFOmetr →