Создайте индекс для огромной производственной таблицы MySQL без блокировки таблицы - PullRequest
84 голосов
/ 22 ноября 2010

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

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

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

Ответы [ 4 ]

109 голосов
/ 10 января 2013

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

https://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html

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

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

Из приведенного выше ответа:

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

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

Выполнение операций UPDATE над таблицей будет BLOCK во время создания индекса.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 и не допускать сбоя доступности.Круговые мастера:

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

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

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

Percona's pt-online-schema-change

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

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

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

RDS

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

53 голосов
/ 18 февраля 2014

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

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

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

ALTER TABLE my_table ADD INDEX my_table__idx (my_column), ALGORITHM=INPLACE, LOCK=NONE;
14 голосов
/ 17 марта 2016

Обновление 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

3 голосов
/ 03 сентября 2015

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

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

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

...