Создайте индекс для огромной производственной таблицы MySQL без блокировки таблицы

106

Мне нужно создать индекс для таблицы MySQL ~ 5M строк. Это производственная таблица, и я боюсь, что все будет полностью заблокировано, если я запущу оператор CREATE INDEX ...

Есть ли способ создать этот индекс без блокировки вставок и выборок?

Просто интересно, я не должен останавливаться, создавать индекс и перезагружать свою систему!

n0cturnal
источник
1
убедитесь, что ваши myisam_sort_buffer_size и myisam_max_sort_file_size достаточно велики.
Джон Блэк,

Ответы:

132

[2017] Обновление: MySQL 5.6 поддерживает онлайн-обновления индекса.

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html#online-ddl-index-syntax-notes

В MySQL 5.6 и выше таблица остается доступной для операций чтения и записи, пока индекс создается или удаляется. Операторы CREATE INDEX или DROP INDEX завершаются только после завершения всех транзакций, обращающихся к таблице, так что начальное состояние индекса отражает самое последнее содержимое таблицы. Ранее изменение таблицы во время создания или удаления индекса обычно приводило к тупиковой ситуации, которая отменяла инструкции INSERT, UPDATE или DELETE для таблицы.

[2015] Обновление таблицы указывает на блокировку записи в MySQL 5.5

Из ответа выше:

«Если вы используете версию выше 5.1, индексы создаются, когда база данных находится в оперативном режиме. Так что не беспокойтесь, вы не прервете использование производственной системы».

Это **** FALSE **** (по крайней мере, для таблиц MyISAM / InnoDB, которые используют 99,999% людей. Clustered Edition отличается.)

Выполнение операций UPDATE с таблицей БЛОКИРУЕТ, пока создается индекс. MySQL действительно очень глуп в этом (и в некоторых других вещах).

Тестовый сценарий:

(   
  for n in {1..50}; do
    #(time mysql -uroot -e 'select  * from website_development.users where id = 41225\G'>/dev/null) 2>&1 | grep real;
    (time mysql -uroot -e 'update website_development.users set bio="" where id = 41225\G'>/dev/null) 2>&1 | grep real;
  done
) | cat -n &
PID=$!
sleep 0.05
echo "Index Update - START"
mysql -uroot website_development -e 'alter table users add index ddopsonfu (last_name, email, first_name, confirmation_token, current_sign_in_ip);'
echo "Index Update - FINISH"
sleep 0.05
kill $PID
time mysql -uroot website_development -e 'drop index ddopsonfu on users;'

Мой сервер (InnoDB):

Server version: 5.5.25a Source distribution

Вывод (обратите внимание, как 6-я операция блокируется на ~ 400 мсек, необходимых для завершения обновления индекса):

 1  real    0m0.009s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.012s
 5  real    0m0.009s
Index Update - START
Index Update - FINISH
 6  real    0m0.388s
 7  real    0m0.009s
 8  real    0m0.009s
 9  real    0m0.009s
10  real    0m0.009s
11  real    0m0.009s

Против операций чтения, которые не блокируются (поменяйте местами комментарий строки в скрипте):

 1  real    0m0.010s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.010s
 5  real    0m0.009s
Index Update - START
 6  real    0m0.010s
 7  real    0m0.010s
 8  real    0m0.011s
 9  real    0m0.010s
...
41  real    0m0.009s
42  real    0m0.010s
43  real    0m0.009s
Index Update - FINISH
44  real    0m0.012s
45  real    0m0.009s
46  real    0m0.009s
47  real    0m0.010s
48  real    0m0.009s

Обновление схемы MySQL без простоев

Таким образом, я знаю только один способ обновить схему MySql и избежать перебоев в доступности. Круговые мастера:

  • На Мастере А работает ваша база данных MySQL
  • Запустите мастер B и заставьте его реплицировать записи от мастера A (B является подчиненным устройством A)
  • Выполните обновление схемы на Мастере Б. Во время обновления он будет отставать.
  • Пусть Мастер Б. догонит. Неизменяемый: изменение схемы ДОЛЖНО допускать обработку команд, реплицированных из схемы понижающей версии. Изменения индексации подходят. Обычно подходят простые добавления столбцов. Удаление столбца? возможно нет.
  • АТОМИЧЕСКИ поменяйте местами всех клиентов с мастера A на мастер B.Если вы хотите быть в безопасности (поверьте мне, вы это делаете), вы должны убедиться, что последняя запись на A реплицируется на B ПЕРЕДB делает первую запись. Если вы разрешаете одновременную запись 2+ мастерам, ... вы лучше понимаете репликацию MySQL на ГЛУБОКОМ уровне, иначе вы попадете в мир боли. Сильная боль. Например, у вас есть столбец АВТОИНКОРМЕНТ ??? вы облажались (если вы не используете четные числа для одного мастера и шансы на другом). НЕ верьте, что репликация MySQL «делает правильные вещи». Это НЕ умно и не спасет. Это немного менее безопасно, чем копирование журналов двоичных транзакций из командной строки и их воспроизведение вручную. Тем не менее, отсоединить всех клиентов от старого мастера и переключить их на новый мастер можно за несколько секунд, что намного быстрее, чем ожидание многочасового обновления схемы.
  • Теперь Мастер Б ваш новый хозяин. У вас есть новая схема. Жизнь хороша. Выпей пива; худшее позади.
  • Повторите процесс с Мастером A, обновив его схему так, чтобы он стал вашим новым второстепенным мастером, готовым вступить во владение в случае, если ваш основной мастер (сейчас мастер B) потеряет силу или просто выйдет из строя и умрет на вас.

Это не простой способ обновить схему. Работоспособен в серьезной производственной среде; Да, это так. Пожалуйста, пожалуйста, пожалуйста, если есть более простой способ добавить индекс в таблицу MySQL без блокировки записи, дайте мне знать.

Поиск в Google привел меня к статье, в которой описывается похожая техника. Более того, они советуют пить в тот же момент в продолжении (обратите внимание, что я написал свой ответ до чтения статьи)!

Изменение схемы pt-online-схемы Percona

В статье, на которую я ссылался выше, говорится об инструменте pt-online-schema-change , который работает следующим образом:

  • Создайте новую таблицу с той же структурой, что и исходная.
  • Обновить схему в новой таблице.
  • Добавьте триггер в исходную таблицу, чтобы изменения синхронизировались с копией.
  • Копирование строк из исходной таблицы партиями.
  • Переместите исходную таблицу в сторону и замените ее новой.
  • Отбросьте старую таблицу.

Сам никогда не пробовал. YMMV

RDS

В настоящее время я использую MySQL через RDS Amazon . Это действительно изящный сервис, который объединяет MySQL и управляет им, позволяя добавлять новые реплики чтения с помощью одной кнопки и прозрачно обновлять базу данных для всех SKU оборудования. Это действительно удобно. У вас нет доступа к базе данных СУПЕР, поэтому вы не можете напрямую подключиться к репликации (это благословение или проклятие?). Однако вы можете использовать продвижение реплики для чтения, чтобы внести изменения в схему на ведомом устройстве, доступном только для чтения, а затем продвинуть это ведомое устройство, чтобы оно стало вашим новым главным. Точно такой же трюк, как я описал выше, но его гораздо проще выполнить. Они по-прежнему мало что делают, чтобы помочь вам с переключением. Вам необходимо перенастроить и перезапустить приложение.

Дэйв Допсон
источник
3
pt-online-schema-change отлично работает даже при репликации master-slave. Я использовал его для динамической миграции в занятой чтением таблице 20M + записей на нашей производственной главной базе данных с двумя подчиненными устройствами репликации без каких-либо сбоев или простоев. Подготовка сценария занимает некоторое время, и мне обычно приходится создавать файл .sql, содержащий необработанное изменение SQL, и файл .sh в качестве оболочки для запуска того же SQL, но в формате фрагмента (без ALTER TABLE). Вы можете запускать несколько команд с помощью pt-online-schema-change, объединяя их в цепочку и разделяя их запятыми.
Alex Le
-1; Я не знаю о более старых версиях, но я знаю, что создание индекса не блокирует одновременный DML в MySQL 5.6+ (для которого RC существовал на момент написания этого ответа и который был официально выпущен, когда этот ответ был продолжен отредактировано в мае 2013 г.), потому что я полагался на это, чтобы запускать многочасовое создание индексов для производственных таблиц, все еще принимая вставки. И хотя вы можете быть правы в отношении создания индекса, блокирующего DML в версии 5.5 и ниже, продемонстрированная здесь субсекундная задержка не совсем убедительна.
Марк Эмери
@MarkAmery - поведение блокировки - это поведение блокировки, а 400 мс - это вечность. MySQL 5.5 блоки для обновления индекса. Создайте большую тестовую базу данных, и она будет блокироваться на секунды, часы или дни. Я написал этот пост до того, как в MySQL 5.6 были обновлены онлайн-схемы, поэтому мой исходный контент не отражает этот факт. Я обновил сообщение, чтобы отразить новую доступную информацию.
Дэйв Допсон
@DaveDopson, вы на 100% уверены, что блокируются только операции UPDATE?
toto_tico
Так было с версией, которую я тестировал.
Дэйв Допсон
67

Как показано в этом сообщении в блоге , ALTER TABLEмеханизм InnoDB был полностью переработан для MySQL 5.6.

(Эксклюзивный обзор этой темы можно найти в документации MySQL, которую можно прочитать после обеда.)

Чтобы добавить индекс в таблицу без блокировки, приводящей к UPDATE/ INSERT, можно использовать следующий формат оператора:

ALTER TABLE my_table ADD INDEX my_table__idx (my_column), ALGORITHM=INPLACE, LOCK=NONE;
Нарисовался
источник
4
Предостережение: dba.stackexchange.com/questions/138363/…
Александр Торстлинг
16

Обновление MySQL 5.6 (февраль 2013 г.): теперь вы можете выполнять операции чтения и записи во время создания индекса даже с таблицами InnoDB - http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index -overview.html

В MySQL 5.6 и выше таблица остается доступной для операций чтения и записи, пока индекс создается или удаляется. Операторы CREATE INDEX или DROP INDEX завершаются только после завершения всех транзакций, обращающихся к таблице, так что начальное состояние индекса отражает самое последнее содержимое таблицы. Ранее изменение таблицы во время создания или удаления индекса обычно приводило к тупиковой ситуации, которая отменяла инструкции INSERT, UPDATE или DELETE для таблицы.

и:

В MySQL 5.6 эта функция становится более общей: вы можете читать и писать в таблицы во время создания индекса, и многие другие виды операций ALTER TABLE могут выполняться без копирования таблицы, без блокировки операций DML или того и другого. Таким образом, в MySQL 5.6 и выше мы обычно называем этот набор функций онлайн-DDL, а не быстрым созданием индекса.

из http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_fast_index_creation

Эрик Сабоя
источник
Тогда как можно объяснить анализ Дэйва?
Нихилу Sahu
1
@NikhilSahu Дэйв явно тестировал не MySQL 5.6, а более старую версию. Обратите внимание, что версия 5.6 еще не была выпущена на тот момент, когда Дэйв опубликовал первоначальную версию своего ответа.
Марк Эмери
+1. Мой анализ проводился на MySQL 5.5 (последняя версия была доступна в 2013 году). Я обновляю свой ответ, чтобы отразить новые возможности MySQL 5.6.
Дэйв Допсон
3

pt-online-schema-change - это то, что нужно, если вы действительно хотите убедиться, что миграция не приведет к остановке сайта.

Как я писал в приведенном выше комментарии, у меня есть несколько опытов с pt-online-schema-change в производственной среде. У нас есть основная таблица из 20 миллионов записей и главный -> 2 подчиненных устройства репликации только для чтения. Я выполнил как минимум десятки миграций с pt-online-schema-change от добавления нового столбца, изменения кодировки до добавления нескольких индексов. Мы обслуживаем тонны трафика во время миграции, и у нас не было никаких сбоев. Конечно, вам придется очень тщательно протестировать все сценарии перед запуском в производство.

Я попытался объединить изменения в один скрипт, чтобы pt-online-schema-change копировал данные только один раз. И будьте очень осторожны с изменением имени столбца, так как вы потеряете свои данные. Однако добавление индекса должно быть нормальным.

Алекс Ле
источник
Я не согласен с вашей безоговорочной рекомендацией pt-online-schema-change. Это здорово, но является излишним для многих ситуаций, когда онлайн-возможности DDL MySQL 5.6+ уже работают нормально. Он также имеет ограничения (например, плохая игра с триггерами) и удваивает объем записи, необходимый для каждой вставки в исходную таблицу, пока происходит изменение схемы. Это облагает ваш диск значительно большим налогом, чем обычное изменение схемы в сети, и, следовательно, может «вывести из строя ваш сайт» в обстоятельствах, когда простое изменение схемы сработало бы нормально.
Марк Эмери
Я написал, основываясь на своем реальном опыте работы с pt-online-schema-change в то время, поэтому я не уверен, почему вы назвали мою рекомендацию «неквалифицированной». У нас было по крайней мере 1000+ посетителей на сайте в любой момент, когда я запускал изменения схемы, и, конечно же, ввод-вывод диска был налогом, но наш сайт не падал. Также помогло хорошее кеширование. Я не использовал онлайн-DDL MySQL 5.6+, но, по моему опыту, pt-online-schema-change хорошо справился со своей задачей в нашем случае.
Alex Le
1
@AlexYe Yikes, я имел в виду «неквалифицированный» в смысле «без оговорок», а не в смысле «доставленный кем-то, кто не имеет права комментировать» - последняя интерпретация не приходила мне в голову, пока я не увидел ваш комментарий, и уж точно не не то, что я задумал! т.е. я говорил, что, хотя pt-online-schema-changeэто полезный инструмент, существует очень много ситуаций, в которых обычный онлайн-DDL так же хорош, и несколько случаев, когда он лучше, поэтому любые его рекомендации должны быть осторожными, а не универсальными.
Марк Эмери