[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 оборудования. Это действительно удобно. У вас нет доступа к базе данных СУПЕР, поэтому вы не можете напрямую подключиться к репликации (это благословение или проклятие?). Однако вы можете использовать продвижение реплики для чтения, чтобы внести изменения в схему на ведомом устройстве, доступном только для чтения, а затем продвинуть это ведомое устройство, чтобы оно стало вашим новым главным. Точно такой же трюк, как я описал выше, но его гораздо проще выполнить. Они по-прежнему мало что делают, чтобы помочь вам с переключением. Вам необходимо перенастроить и перезапустить приложение.