Транзакции InnoDB

    InnoDB это транзакционный, реляционный движок работающий на основе MySQL сервера. Начиная с 2001 года он поставляется в стандартной сборке, а с версии 5.1 может устанавливаться в качестве плагина (без необходимости перекомпилировать ядро сервера). Синтаксис очень простой.
    START TRANSACTION;
    ...
    COMMIT; -- или же ROLLBACK; если что-то пошло в логике не так

    Про определение


    Определение транзакционности и реляционности значат во-первых значат полноценную связанность таблиц через FK и как следствие — целостность данных при удалении рядов. С MyIsam как известно приходилось вручную удалять связанные данные в нескольких таблицах, в InnoDB — каскадное удаление одним запросом. Во-вторых поскольку для БД немыслимы параллельные версии данных как в SVN и некому эти версии объединять в одну ветку, но при этом необходима параллельная работа нескольких процессов (пользователей) с одними данными, то в качестве решения становится транзакции.
    Очередь из запросов-автомобилей теперь пополняется атомарной транзакцией-автобусом. Естественно это плохо, поскольку чем длиней и дольше выполняется транзакция тем больше параллельных процессов будут ждать его. Для ускорения работы создаются остановки — типы и уровни блокировки данных. Для InnoDB по умолчанию это блокирование на уровне строки (по PK), тогда как в MyIsam атомарная операция блокирует всю таблицу.


    Тразнактивность = блокировка


    Два движка поэтому нельзя сравнивать — InnoDB из-за транзактивности приходится спускаться на уровень строк, поскольку вероятность очереди к одной и той же строке у двух процессов ниже, следовательно быстрей будет работа. Но как результат — на каждую строку приходится делать флаги блокировки, значит чуть больше памяти. Из-за разницы в уровнях блокировки данных, сравнивать InnoDB с MyIsam по производительности в зависимости от числа процессов достаточно трудно.
    Есть несколько типов блокировок
    • READ (пока я читаю — никто не запишет) — по умолчанию на SELECT ставится
    • WRITE (пока я пишу — никто не прочтёт и не запиет) — по умолчанию на UPDATE ставится
    • LOW_PRIORITY WRITE (дам быстро прочитать если кто-то ждёт)

    В качестве ликбеза — блокировать можно вручную целую таблицу (но не нужно ибо для InnoDB это убого тормозит все процессы). Повторное блокирование снимает предыдущие блокировки. Блокировать можно и виртуальные таблицы (view)
    LOCK TABLES user WRITE, company READ;
    UNLOCK TABLES;


    Уровни изоляции


    В случаях когда два процесса одновременно и частично затрагивают общие данные то не обязательно все данные будут полностью блокированы. Существуют послабления, когда параллельные транзакции получают доступ к незавершённым транзакциям.
    Текущий уровень можно получить из настроек, можно прописать в настройки или исполнить запросом — как на время транзакции так и на время всего соединения.
    SELECT @@global.tx_isolation;
    SET TRANSACTION ISOLATION LEVEL READ COMMITED;

    По степени точности (строгости блокировки) по убыванию согласно стандарту SQL92 выделяют:
    • SERIALIZEABLE — полная независимость транзакций, в т.ч. своё чтение
    • REPEATABLE READ (повторяющееся чтение) — значение для InnoDB по умолчанию. Чтение общих строк в транзакциях разрешается, но не их изменение.
    • READ COMMITED (чтение фиксированного) — блокировка записи, но общее чтение. Есть проблема повторяющегося чтения, т.е. в первой транзакции несколь раз по разному читаются общие данные, потому что вторая транзакция их меняет.
    • READ UNCOMMITED («грязное» чтение незафиксированного) — никакой блокировки на чтение и запись. При двух одновременных UPDATE поле получит значение последнего изменения в обоих транзакциях. Возможны множество проблем, особенно если до ROLLBACK одной транзакции изменения читает другая.

    В REPEATABLE READ существует проблема фантомной вставки. Поскольку блокируются только ряды на UPDATE, но не на INSERT, то параллельно с транзакцией повторяющегося чтения можно сделать вставку, из-за чего возникнет фантомный ряд. Что-бы этого избежать InnoDB использует три способа блокировки — строка, диапазон и следующая строка на случай вставки (глубже я вчитываться не стал)
    Вся эта теория конечно полезна, но по настоящему они используются реальными запросами.
    1. Чтение с уровенем REPEATABLE READ (блокировка на запись). Ждёт если над данными кто-то работает.
      SELECT... LOCK IN SHARE MODE
    2. Чтение в режиме SERIALIZEABLE (блокировка на чтение и запись)
      SELECT... FOR UPDATE

    При этих запросах на время исполнении транзакции она переходит в новый режим.

    Травматизм deadlock'ов


    Deadlock'и, т.е. тупиковая ситуация одновременных процессов (потоков) которые нуждаются в одних и тех же или зависимых друг от друга данных часто возникают в программировании. InnoDB не исключение. Например если идут две транзакции и каждая хочет изменить ресурсы (строки/диапазон строк) которые сейчас заблокированы. Получается что ни одна транзакция не может закончится.
    В таких ситуациях InnoDB вынуждена откатить одну из транзакций и выдать ошибку
    ERROR 1213 (40001): Deadlock found when trying to get lock; try
    restarting transaction

    Такие проблемы возникают при большой параллельной вставке/изменении/удалении рядов несколькими процессами. MySQL советуют все транзакции снабжать повторным запуском транзакций.
    По теме..


    Оригинал статьи

    Средняя зарплата в IT

    113 000 ₽/мес.
    Средняя зарплата по всем IT-специализациям на основании 10 037 анкет, за 2-ое пол. 2020 года Узнать свою зарплату
    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

    Комментарии 2

      +2
      Перенесите в MySQL?
        0
        SERIALIZEABLE -> SERIALIZABLE

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое