Предотвратит ли блокировка таблицы блокировку строк

У меня есть таблица с более чем 160 миллионами записей, у которой неправильный движок таблицы, поэтому я собираюсь изменить движок. Когда я делаю это без какой-либо подготовки, я получаю сообщение об ошибке из-за размера моего буфера из-за слишком большого количества блокировок строк.

mysql> ALTER TABLE foobar ENGINE=MyISAM;
ERROR 1206 (HY000): The total number of locks exceeds the lock table size

Теперь я хочу заблокировать всю таблицу перед этим действием, а затем разблокировать всю таблицу.

mysql> LOCK TABLES foobar WRITE;

Мой вопрос: замечает ли сервер mysql, что блокировка таблицы уже активна, и пропускает блокировки строк, или же он заблокировал таблицу и теперь также снова блокирует каждую строку, и я снова столкнусь с той же ошибкой?

Я также открыт для любых других предложений, как заменить движок такого большого (и большего) стола самым быстрым способом :)


person Preexo    schedule 19.03.2014    source источник
comment
Проверьте инструмент pt-online-schema-change. Это также должно решить вашу проблему. Но MyISAM... вас не волнуют ваши данные, не так ли? :)   -  person akuzminsky    schedule 19.03.2014
comment
спасибо за совет по поводу инструмента! Я бы предпочел заменить двигатель без каких-либо сторонних инструментов, но, возможно, нет другого способа решить эту проблему. кстати: каждый инструмент делает свою работу;) - MyISAM тоже. Итак, чтобы ответить на ваш вопрос: нет, в данном случае я на самом деле нет, на самом деле это кеш-таблица, но в любом случае... Вопрос больше о фоновых процессах и понимании того, пропускает ли mysql блокировку строк, если блокировка таблицы уже активна: )   -  person Preexo    schedule 19.03.2014


Ответы (2)


Вы можете провести эксперимент:

В первом сеансе запуска:

mysql> LOCK TABLE foobar WRITE;
mysql> ALTER TABLE foobar ENGINE=MyISAM;

Во втором сеансе (т.е. откройте второе окно терминала) запустите:

mysql> SHOW ENGINE INNODB STATUS\G

Внизу в разделе ТРАНЗАКЦИИ вы обнаружите, что ваш поток ALTER выполняется:

---TRANSACTION 69638, ACTIVE 45 sec fetching rows
mysql tables in use 1, locked 1
14626 lock struct(s), heap size 1898936, 5145657 row lock(s)

Ого! Он создает много отдельных блокировок строк, несмотря на действующую LOCK TABLE.

(Это всего лишь пример; вы увидите, что количество блокировок строк со временем увеличивается по мере того, как ALTER TABLE работает с вашей таблицей.)


Поэтому вам нужно гарантировать место для большого количества блокировок строк.

https://dev.mysql.com/doc/refman/5.6/en/innodb-error-codes.html говорит:

  • 1206 (ER_LOCK_TABLE_FULL)

    Общее количество блокировок превышает объем памяти, который InnoDB выделяет для управления блокировками. Чтобы избежать этой ошибки, увеличьте значение innodb_buffer_pool_size. В отдельном приложении обходной путь может состоять в том, чтобы разбить большую операцию на более мелкие части. Например, если ошибка возникает для большого INSERT, выполните несколько меньших операций INSERT.

(выделено мной)

Также прочитайте Сколько памяти действительно блокирует Innodb взять?

Блокировки на уровне строк в Innodb реализуются за счет наличия специальной таблицы блокировок, расположенной в пуле буферов, где можно установить небольшую запись, выделенную для каждого хэша и для каждой строки, заблокированной на этом бите страницы. Теоретически это может дать накладные расходы всего в несколько бит на строку.

Таким образом, для блокировки 160 миллионов строк требуется около 60-80 МБ места в таблице блокировки. Ваш буферный пул может быть слишком мал, чтобы вместить это.

Размер буферного пула InnoDB по умолчанию составлял всего 8 МБ в MySQL 5.1.27 и более ранних версиях. Значение по умолчанию было увеличено до 128 МБ в MySQL 5.1.28.


Повторите ваш комментарий:

каждый инструмент выполняет свою работу ;) - MyISAM тоже

MyISAM не поддерживает атомарность, согласованность, изоляцию или долговечность. Кроме этого, это здорово. :-)

person Bill Karwin    schedule 19.03.2014
comment
Спасибо за помощь! Версия моего сервера 5.5.35-0+wheezy1-log, так что должно хватить... Я только что назначил 1G, давайте посмотрим, как это будет работать. По поводу комментария: Да, нам действительно не нужно ACID с этой таблицей, мы могли бы даже очистить ее и пересобрать кеш, если это не сработает, так что для нас MyISAM великолепен :) - person Preexo; 19.03.2014
comment
Хорошо, если вам не нужны транзакции и данные легко восстанавливаются при повреждении, и вам нравится, что У MyISAM худшая производительность, тогда дерзайте! - person Bill Karwin; 19.03.2014
comment
Билл, вы сначала пробовали auto_commit = 0, чтобы блокировка таблицы не снималась сразу? - person Marcus Adams; 19.03.2014
comment
@MarcusAdams, явные блокировки таблиц не ограничиваются одной транзакцией. Они остаются в силе до тех пор, пока вы явно не разблокируете столы или сеанс не завершится. - person Bill Karwin; 19.03.2014
comment
Я полагаю, меня смутило это: все блокировки InnoDB, удерживаемые транзакцией, освобождаются, когда транзакция фиксируется или прерывается. Таким образом, нет особого смысла вызывать LOCK TABLES для таблиц InnoDB в режиме autocommit=1, потому что полученные блокировки таблиц InnoDB будут сняты немедленно. из здесь. - person Marcus Adams; 19.03.2014
comment
@MarcusAdams, ага, но блокировки таблиц, созданные LOCK TABLES, устанавливаются (и, предположительно, снимаются) уровнем MySQL над уровнем механизма хранения. См. dev.mysql.com/doc/refman/5.6/ en/innodb-locks-set.html (в последнем пункте внизу страницы). - person Bill Karwin; 19.03.2014
comment
эксперимент действительно отвечает на вопрос, спасибо! - person Preexo; 20.03.2014
comment
Будет ли 60-80 МБ места относиться к объему innodb_buffer_pool_size? - person javiniar.leonard; 08.02.2016
comment
@javiniar.leonard, да, Innodb хранит блокировки в специальной внутренней таблице блокировок, которая использует ту же память, что и innodb_buffer_pool_size. См. mrothouse.wordpress.com/2006/10/20/mysql- ошибка-1206 - person Bill Karwin; 08.02.2016

Обычно, если ваш пул буферов InnoDB недостаточно велик, чтобы удерживать блокировки строк для всех строк в таблице (что иногда необходимо), вы увеличиваете размер пула буферов InnoDB (innodb_buffer_pool_size).

Попробуйте увеличить innodb_buffer_pool_size до 128 МБ.

Если у вас все еще есть проблемы, вы всегда можете попробовать создать новую таблицу MyISAM, а затем выполнить INSERT INTO ... SELECT FROM ..., чтобы скопировать данные из таблицы InnoDB в таблицу MyISAM. Вы можете копировать строки по частям, чтобы уменьшить блокировки строк.

person Marcus Adams    schedule 19.03.2014
comment
Спасибо за совет, копирование данных из старой таблицы в новую (с правильным движком) — это следующий шаг, который я попробую, если ALTER по-прежнему не работает. Я просто подумал, что mysql делает то же самое внутри (копирование через временную таблицу на ALTER), поэтому какой смысл делать это вручную... Но, возможно, я был неправ, и это решение;) Я посмотрю завтра. - person Preexo; 19.03.2014
comment
InnoDB создает общие блокировки для строк из исходной таблицы во время INSERT INTO ... SELECT FROM .... Например, это может привести к блокировке потока репликации на ведомом устройстве, когда вы вставляете множество строк во временные таблицы. - person Bill Karwin; 19.03.2014