Как определить, что две операции разных транзакций в расписании являются конфликтующими?
Две операции конфликтуют, если они принадлежат разным транзакциям, обращаются к одному объекту данных, и хотя бы одна из них является записью. Поэтому конфликтуют пары «чтение—запись», «запись—чтение» и «запись—запись», но не «чтение—чтение».
Последовательное выполнение транзакций проще всего анализировать, но оно ограничивает производительность. Поэтому СУБД разрешают конкурентное выполнение, сохраняя требование сериализуемости: результат должен быть эквивалентен некоторому последовательному порядку.
Для проверки этого свойства понадобилось отделять операции, которые действительно влияют друг на друга, от независимых. Так возник анализ конфликтов и построение графа зависимостей между транзакциями.
Пусть две транзакции обращаются к одному значению. Если обе только читают его, порядок операций не меняет результат. Но запись может изменить значение, от которого зависит другая операция, поэтому порядок уже становится существенным.
Ошибочное признание независимых операций конфликтующими приведёт к излишнему ограничению конкурентности. Если же настоящий конфликт не обнаружить, СУБД может принять некорректное расписание за безопасное и допустить результат, неэквивалентный последовательному выполнению.
Пара операций является конфликтующей при одновременном выполнении трёх условий:
Отсюда следуют три конфликтующие комбинации: чтение—запись, запись—чтение и запись—запись. Пара чтение—чтение конфликтом не считается: операции не изменяют состояние и могут быть переставлены без изменения результата.
Например, если транзакция T1 читает значение X, а T2 позже изменяет X, между ними возникает зависимость: результат T1 относится к версии X, существовавшей до или после изменения T2 в зависимости от порядка. Аналогично, если T1 записывает X, а T2 читает X, порядок определяет, увидит ли T2 новое значение.
При конфликте «запись—запись» порядок особенно важен: последняя запись может затереть результат первой. Даже если итоговое значение случайно совпало, само расписание всё равно содержит потенциальную зависимость.
Для анализа обычно создают ориентированное ребро от транзакции с первой операцией к транзакции со второй. Если граф зависимостей имеет цикл, расписание не является конфликтно-сериализуемым: невозможно переставить неконфликтующие операции так, чтобы получить эквивалентное последовательное выполнение.
Это критерий именно конфликтной сериализуемости. Отсутствие цикла гарантирует возможность такого преобразования, но СУБД может использовать более сложные модели сериализуемости, а конкретный способ обнаружения конфликтов зависит от уровня изоляции и реализации блокировок или версий данных.
В системе две транзакции работают с одной строкой заказа. Первая читает статус заказа, вторая обновляет этот статус. Эти операции конфликтуют, поэтому их порядок нельзя игнорировать при проверке сериализуемости.
Вариант с полной последовательной блокировкой всех транзакций прост для рассуждений, но резко снижает пропускную способность. Вариант с игнорированием чтений быстрее, однако может допустить некорректный порядок зависимостей. Вариант с анализом конфликтов сохраняет конкурентность для независимых операций и ограничивает только действительно связанные действия.
На практике выбирают блокировки, MVCC или сериализуемый контроль конкурентности в зависимости от СУБД и требований. Если важна строгая корректность инвариантов, конфликт может привести к ожиданию или ошибке сериализации; приложение должно уметь повторить всю транзакцию, а не отдельную операцию. Результат — независимые операции выполняются параллельно, а опасные зависимости обнаруживаются или предотвращаются.
1. Конфликтуют ли операции над разными строками одной таблицы?
Нет, само совпадение таблицы недостаточно. При построчном анализе операции над разными строками обращаются к разным объектам и не конфликтуют. Однако диапазонные условия могут затрагивать не только существующие строки: для предотвращения фантомов сериализуемая СУБД может учитывать диапазон или предикат как область конфликта.
2. Всегда ли наличие конфликта означает ошибку?
Нет. Конфликт означает зависимость от порядка, но допустимый последовательный порядок может существовать. Ошибка возникает, например, когда совокупность зависимостей образует цикл либо выбранный уровень изоляции не может безопасно продолжить выполнение и прерывает транзакцию.
3. Почему чтение—чтение не считается конфликтом, даже если транзакции читают разные версии?
Обе операции только наблюдают состояние и сами его не меняют. Их перестановка не создаёт причинной зависимости между результатами. Разные версии могут быть следствием выбранной модели изоляции, но это уже вопрос согласованности снимка и видимости данных, а не конфликтности самих операций.