Pull to refresh

Comments 17

Во всех статьях такого типа ОЧЕНЬ не хватает описания в каких случаях какой тип изоляции выбирать. А-то складывается впечатление, что можно включить serializable и не париться. Не пишут о производительности на разных режимах.
Спасибо
Пример для read uncommitted есть, для repeatable read дописал.

Про производительность добавил предложение вначале. Если Вы конечно не имели ввиду конкретные бенчмарки :)

Алгоритм примерно такой.
Сначала надо выбрать минимальный уровень изоляции, который гарантирует корректность поведения в данной транзакции (включая корректность данных с одной стороны и отсутствие взаимоблокировок с другой). Замечание про "в данной транзакции" весьма важное.
Обычно это решение достаточно легко следует из того, что вы делаете в транзакции.
Например:


  • Вывод списка в грид/на форму — обычно read committed, изредка read uncommitted (только в некоторых СУБД имеет смысл, в частности в старых версиях MS SQL, или если не используете RCSI)
  • Отчёты/формы, состоящие из одного запроса с соединениями/объединениями (join или union) — read committed
  • Отчёты/формы, состоящие из нескольких последовательных запросов или использующие временные таблицы — надо оценить, насколько тут нужен repeatable read (и действия должны быть в одной транзакции, иначе repeatable read не имеет смысла). Если не нужен, то read committed, если нужен, то repeatable read.
  • Пишущие транзакции (с проверкой условий/остатков, из нескольких запросов) — используйте по умолчанию не ниже repeatable read.
  • В MS SQL лучше (с точки зрения корректности данных и отсутствия взаимоблокировок) в пишущей транзакции для тех таблиц, которые меняются в данной транзакции использовать как можно раньше serializable. В других СУБД в зависимости от того, можете ли нарваться на фантомы.

Важно, что всегда сначала выбираем минимальный уровень, обеспечивающий корректную работу, и только потом смотрим, как это можно улучшить.


После того, как определились с базовым уровнем изоляции начинаем смотреть (правильность, производительность одного потока, производительность параллельных соединений с сервером, взаимоблокировки и блокировки/race condition горячих мест) и искать компромиссы. Тут уже парой абзацев не отделаться (статья превратится в книгу) — ситуаций и компромиссов даже в одной СУБД, даже типовых быстро становятся десятки. Цикл типичный: сбор информации, гипотеза, проверка, изменение, проверка применимости, внедрение и так по кругу.

Пожалуй, ваша заметка больше вредна чем полезна, легко может запутать начинающих разработчиков, особенно пример с Repeatable read. Да к чему здесь docker? Вы так сильно ненавидите ваш пакетный менеджер?;)
Ну уж извините, пытался максимально просто объяснить, как разбирался сам на самых простых примерах.

Docker здесь для того, чтобы любой желающий, скопировав пару файлов мог сам повторить примеры в том же самом окружении, где это делал я.
Чисто из любопытства, т.к. казалось, что данная статья помогла понять некоторые важные моменты. Что в статье не так/запутывает?

Да хотя бы тем, что феномены не объяснены. А значит, что из этой статьи человек не поймёт, как минимум разницу serializable/repeatable read. Это, кстати, весьма индикативный вопрос, например, часто кандидат на собеседовании говорит "я ваще крут в СУБД и уровни изоляции вдоль и поперёк", а на вопрос разницы serializable/repeatable read хотя и говорит "фантомы", но привести пример и объяснить что это за фантомы не может.
Ну и то, что уровни изоляции надо объяснять либо без СУБД вообще, либо с одной СУБД. Потому что реализации НАСТОЛЬКО разные, что потом у человека, которому объясняли, каша в голове.


ЗЫ: Это только моё мнение, на основании моего опыта объяснения уровней изоляций лет около 15.

Резонное замечание, и особо отметил бы важность абстрагирования от СУБД в том числе и в данном вопросе.

Как минимум по двум причинам:

1) СУБД бывают разные, а понимать суть по-прежнему нужно - это более-менее очевидно

2) А вот что менее очевидно: понимать суть нужно даже независимо от того, используется ли СУБД вообще или нет. Поскольку любая СУБД, да и вообще хранилище - это лишь инструмент для реализации некоторых задач. А когда мы говорим о каких-то задачах, мы чаще всего имеем ввиду какую-то бизнес-логику, которая, очевидно, понятия не имеет о каких-либо СУБД. И транзакции в данном смысле надо понимать не как транзакции в СУБД, а как "бизнес-транзакции", которые могут быть реализованы на самом разнообразном стэке, в том числе и быть распределены между различными сервисами (у каждого из которых может быть как своя СУБД, так и не быть вовсе). Однако обеспечить изолированность этих транзакции может быть по-прежнему нужно.

Стоит отметить, что разные СУБД имеют разную [b]реализацию[/b] этих уровней изоляции. Сами-то уровни будут работать одинаково (как им предписано стандартом), но вот процесс выполнения запроса с клиентской стороны будет разным (например, будет ли блокироваться и висеть в ожидании запрос, выполняющий SELECT, если есть другая незавершенная транзакция, выполнившая UPDATE над данной таблицей? ). Причём даже в рамках одной СУБД существуют опции, меняющие поведение в рамках одних и тех уровней изоляции. Например, в MS SQL SERVER есть замечательная опция READ_COMMITTED_SNAPSHOT, включив которую активируется режим "версионирования" строк, в котором в приведённом мной выше примере SELECT не блокируется даже при уровне изоляции READ_COMMITTED, потому что незакомиченный UPDATE создаёт внутри СУБД "отдельные версии" обновлённых строк.


Да что я вам тут пишу, вон кто-то уже всё расписал:
https://habr.com/ru/post/305600/

Вы в разделе про Read committed на шаге 4 говорите, что удаление строки, также как и изменение строки приводит к unrepeatable read:
«Теперь Т2 видит все, что сделала Т1. Это так называемые феномен неповторяющегося чтения, когда мы видим обновленные и удаленные строки (UPDATE, DELETE), и феномен чтения фантомов, когда мы видим добавленные записи (INSERT).»

На самом деле это чтение фантомов.
Другое дело, что Delete можно поймать на уровне изоляции ReadComitted, и нельзя на Repeatable Read.
Хм, а что же тогда такое феномен неповторящегося чтения для уровня read committed? Если DELETE — это чтение фантомов
Да, похоже, что я ошибся.
Sign up to leave a comment.

Articles

Change theme settings