MySQL / InnoDB реализует истинную сериализуемую изоляцию? - PullRequest
18 голосов
/ 07 июня 2011

Из документации MySQL не совсем ясно, реализует ли механизм InnoDB истинную сериализуемую изоляцию 1 или изоляция снимка , который также часто называют «сериализуемым». Какой это?

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

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

Ответы [ 5 ]

12 голосов
/ 13 ноября 2011

UPDATE:

См. Комментарии, похоже, что исправлено в MySQL 5.5 , в этих примерах у нас все еще есть блокировка таблицы, и блокировку индекса следующего ключа невозможно обмануть, AFAIK.

Оригинал:

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

Итак, я сделал тестов . 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):

T1

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

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

T2

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

Результат 300.

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

T1

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

==> Ожидание (замок на месте)

T2

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);

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

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

T1

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

Результат - 30.

T2

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

Результат 300.

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

T1

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

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

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

T1

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

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

T2

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

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

T1:

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!
+-------+-------+

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

9 голосов
/ 12 декабря 2011

Существуют ли какие-либо полностью свободные СУБД производственного качества?

Postgres поддерживает истинную сериализуемую изоляцию , начиная с версии 9.1 .Это, безусловно, квалифицируется как «абсолютно бесплатно» и «качество продукции».

1 голос
/ 21 апреля 2013

Вы уверены, что используете «сериализуемые» транзакции.Чтобы быть уверенным, вы должны использовать «УСТАНОВИТЬ УРОВЕНЬ ИЗОЛЯЦИИ ТРАНЗАКЦИИ СЕРИАЛИЗИРУЕМЫХ»;так что весь сеанс становится сериализуемым, а не только следующая транзакция.

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

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

0 голосов
/ 08 июня 2011

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

0 голосов
/ 07 июня 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...