MySQL: усеченная таблица в транзакции? - PullRequest
33 голосов
/ 12 мая 2011

У меня есть таблица InnoDB, которую нужно обновлять каждые десять минут в пределах от 60 до 200 тыс. Записей.Наш подход к этому моменту заключался в следующем:

  1. Отключить автокоммит
  2. Усечь таблицу
  3. Выполнить отдельные запросы и дополнительные вычисления (с использованием PHP)
  4. Вставить новые записи
  5. Зафиксировать

После выполнения операции усечения данные немедленно удаляются и больше не доступны из интерфейса пользователя.Для наших пользователей это довольно смущает, хотя в течение примерно 30 секунд сценарий обнаруживает операцию фиксации и таблица заполняется заново.

Я подумал, что, возможно, смогу завершить всю операцию, включая Truncate, в транзакции, и что это может сократить промежуток времени, в течение которого таблица кажется пустой для пользователей.Поэтому я изменил SET AUTOCOMMIT=0 на START TRANSCATION.

Yikes! Это имело противоположное желаемому эффекту!Теперь операция TRUNCATE по-прежнему происходит в начале скрипта, но для выполнения операций INSERT внутри транзакции требуется намного дольше , так что к моменту выполнения операции COMMITи данные в таблице снова доступны, прошло около десять минут!

Что может вызвать это?По правде говоря, я не ожидал каких-либо изменений, потому что у меня сложилось впечатление, что инициирование транзакции в основном просто отключает Autocommit в любом случае ??

Ответы [ 3 ]

55 голосов
/ 12 мая 2011

http://dev.mysql.com/doc/refman/5.1/en/truncate-table.html

В соответствии с этим URL, начиная с MySQL 5.1.32, TRUNCATE TABLE - это DDL, а НЕ DML, как DELETE.Это означает, что TRUNCATE TABLE приведет к неявному COMMIT в середине блока транзакции.Таким образом, используйте DELETE FROM на столе, который необходимо очистить, вместо TRUNCATE TABLE.

Даже DELETE FROM tblname; можно откатить.Откат может занять некоторое время, поэтому убедитесь, что InnoDB правильно настроен для обработки времени транзакции для таких возможностей отката.

54 голосов
/ 12 мая 2011

Лучший способ сделать это - вставить данные в новую таблицу, а затем использовать переименовать в обеих таблицах, чтобы поменять их местами. Одно переименование - это все, что нужно для свопинга, и это атомарное действие, которое означает, что пользователи даже не смогут обнаружить, что это произошло, за исключением появления новых данных. Затем вы можете обрезать / удалить старые данные.

0 голосов
/ 12 мая 2011

Из вашего описания я не могу объяснить вашу разницу во времени.Единственное, что приходит на ум, это то, что вы на самом деле не оборачиваете вставки в одну транзакцию, а зацикливаете ее.

Ключевое различие с SET AUTOCOMMIT = 0 состоит в том, что если он уже0, он ничего не будет делать, где, как и при START TRANSACTION, вы инициируете суб-транзакцию в рамках текущей транзакции.

...