Подтвердить что ты не робот

Использует ли MySQL/InnoDB истинную сериализуемую изоляцию?

В документации MySQL не совсем ясно, работает ли движок InnoDB с помощью истинной сериализуемой изоляции 1 или > , что часто называют "сериализуемым" . Кто из них?

Если MySQL InnoDB этого не делает, есть ли какие-либо совершенно свободные, РСУБД производственного качества, которые делают?

1 где "истинная сериализуемая изоляция" означает отсутствие не только аномалий чтения в соответствии со стандартом SQL, но также аномалию косой записи, более подробно объясненную .

4b9b3361

Ответ 1

есть ли абсолютно бесплатная, РСУБД производственного качества, которая делает?

Postgres поддерживает истинную сериализуемую изоляцию начиная с версии 9.1. Он, безусловно, квалифицируется как "совершенно свободный" и "производственный".

Ответ 2

UPDATE:

См. комментарии, это, по-видимому, исправлено в MySQL 5.5, с этими примерами у нас все еще есть блокировка таблицы, а блокировка следующей клавиши индекса не может быть обманута, AFAIK.

Оригинал:

Нашел ваш вопрос вчера, и мне было интересно узнать о модели надежности MVCC от InnoDb.

Итак, я сделал несколько тестов. MySQL 5.1.37. Хорошим тестом для проблемы сериализации является тот, который представлен в postgrESQL 9.0 MVCC документации, в этой главе Сериализуемая изоляция против истинной последовательной совместимости мы можем видеть предел модели MVCC по сериализуемости, если не выполняется предикатная блокировка.

Итак, давайте протестируем его на MySQL:

CREATE TABLE t1 (
 class integer,
 value integer
) ENGINE=InnoDB;

INSERT INTO t1 (`class`,`value`) VALUES
  (1,10),
  (1,20),
  (2,100),
  (2,200);

Теперь мы откроем два разных соединения, чтобы иметь две параллельные транзакции (T1 и T2):

Т1:

SET TRANSACTIOn ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT SUM(value) FROM t1 WHERE class = 1;

Результат равен 30.

Т2:

 SET TRANSACTIOn ISOLATION LEVEL SERIALIZABLE;
 BEGIN;
 SELECT SUM(value) FROM t1 WHERE class = 2;

Результат 300.

Теперь возникает проблема сериализации. Если T1 вставляет строку, отображающую выбор из T2 недействительным (здесь T2 делает то же самое).

Т1:

INSERT INTO t1 (`class`,`value`) VALUES (2,30);

== > Ожидание (блокировка на месте)

Т2:

INSERT INTO t1 (`class`,`value`) VALUES (1,300);

== > ОШИБКА 1213 (40001): обнаружен тупик при попытке получить блокировку; попробуйте перезапустить транзакцию

T1 теперь преуспевает в своей вставке, t2 имеет ROLLBACK, хорошую сериализуемость.

Это может привести к ошибке PostgreSQL 9.0 (все меняется на 9.1, но это еще одна проблема). Фактически только одна транзакций может выполнять вставку в таблице. Даже если мы попытаемся вставить на class=3 с.

INSERT INTO t1 (`class`,`value`) VALUES (3,30);

Мы увидим блокировку ожидания и взаимоблокировки в случае проблем. Похоже, у нас есть блокировка предикатов в MySQL... Но на самом деле это реализация блокировки в следующем ключе в InnoDB.

Innodb выполняет блокировки строк с некоторыми зазорами, также заблокированными по индексам. Здесь у нас нет индексов в таблице, похоже, что MySQL решил заблокировать таблицу.

Итак, попробуйте протестировать блокировку следующего ключа, чтобы убедиться, что это обеспечивает сериализуемость. Первый откат текущей транзакции (T1). Затем создайте индекс.

CREATE index t1class ON t1 (class);

Теперь повторите тест. Успех, сериализуемость по-прежнему применяется. Хорошие новости.

Но с индексом на месте я думаю, что блокировка следующего ключа и блокировки строк сделаны в индексе. Это означает, что мы должны иметь возможность выполнять вставку, если она не влияет на параллельную транзакцию... , и здесь возникает большая проблема.

Т1:

SET TRANSACTIOn ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT SUM(value) FROM t1 WHERE class = 1;

Результат равен 30.

Т2:

 SET TRANSACTIOn ISOLATION LEVEL SERIALIZABLE;
 BEGIN;
 SELECT SUM(value) FROM t1 WHERE class = 2;

Результат 300.

Здесь мы собираемся сделать несвязанную вставку на T1, теперь, когда у нас есть индекс, это будет успешным:

Т1:

INSERT INTO t1 (`class`,`value`) VALUES (3,30);

Оба могут выполнить вставку (здесь я сделал только одну), что нормально. Прогностическая блокировка не применяется, запросы SELECT не выполняются на class=3. Похоже, что блокировка следующего ключа работает лучше, если мы дадим ему хорошие индексы (нет блокировки таблиц на вставках).

Теперь мы пытаемся вставить блокировку следующего ключа, в строке, соответствующей выбору T2 (class= 2):

Т1:

INSERT INTO t1 (`class`,`value`) VALUES (2,30);

Уч. Это успешно!

Т2:

INSERT INTO t1 (`class`,`value`) VALUES (1,300);

== > Ожидание. Там все еще есть замок. Будем надеяться.

Т1:

COMMIT;

T2: (когда замок заблокирован, вставка выполнена)

SELECT SUM(value) FROM t1 WHERE class = 2;
COMMIT;

Все еще здесь 300. Кажется, сериализуемость ушла.

select * from t1;
+-------+-------+
| class | value |
+-------+-------+
|     1 |    10 | 
|     1 |    20 | 
|     2 |   100 | 
|     2 |   200 | 
|     3 |    30 | <-- test
|     2 |    30 | <-- from trans1
|     1 |   300 | <-- from trans2 ERROR!
+-------+-------+

Результат: Вставляя новую несвязанную строку перед вставкой строки, влияющей на запрос параллельной транзакции, мы подделали механизм блокировки следующего ключа. Или, по крайней мере, это то, что я понимаю из моих тестов. Поэтому я бы сказал, не доверяет движку для истинной сериализуемости. Когда в транзакции есть агрегаты, лучше всего вручную заблокировать таблицу, преобразуйте проблему сериализации в реальной ситуации только одного парня, никаких сюрпризов! Другие проблемы сериализации в примерах - это проверки ограничений (проверьте, что сумма остается положительной после вашей операции), у вас также есть блокировки в этих случаях.

Ответ 3

Вы уверены, что используете "сериализуемые" транзакции. Разумеется, вы должны использовать "СЕТЕВОЙ УРОВЕНЬ УСТРОЙСТВА ИЗОЛЯЦИИ", SERIALIZABLE; так что весь сеанс становится сериализуемым, а не только следующей транзакцией.

Я тестирую с 5.5.29 на OSX

и когда я пытаюсь вставить (3,30) в T1, после создания индекса в классе, транзакция ждет и прерывается после истечения времени ожидания блокировки. (T2 все еще продолжается)

Ответ 4

Читайте больше по ссылке которую вы предоставили, говорится, что использование режима "repeatable-read" (по умолчанию для innodb) избавляется от чтения аномалий, как вы упомянули в качестве одного из ваших требований. Кроме того, прочитав вторую ссылку, выясняется, что обработка аномалий записи смещается к конечному пользователю. В статье упоминаются Oracle Select for Update, которые MySQL также поддерживает. Я не уверен, что это соответствует вашим требованиям, но это должно помочь вам немного.

Ответ 5

Я не верю, что MySQL реализует сериализуемую изоляцию, которая, как я понимаю, потребует возможности отката, который определенно не поддерживает. Для получения дополнительной информации прочитайте здесь.