ALTER TABLE без блокировки стола? - PullRequest
101 голосов
/ 21 января 2009

При выполнении инструкции ALTER TABLE в MySQL вся таблица блокируется на чтение на время выполнения инструкции. Если это большая таблица, это означает, что операторы вставки или обновления могут быть заблокированы на долгое время. Есть ли способ сделать «горячее изменение», например, добавить столбец таким образом, чтобы таблицу можно было обновлять на протяжении всего процесса?

В основном меня интересует решение для MySQL, но я бы заинтересовался другими СУБД, если MySQL не может этого сделать.

Чтобы уточнить, моя цель - просто избежать простоя, когда новая функция, которая требует дополнительного столбца таблицы, запускается в производство. Любая схема базы данных будет изменяться со временем, это просто факт жизни. Я не понимаю, почему мы должны признать, что эти изменения неизбежно приведут к простоям; это просто слабо.

Ответы [ 19 ]

58 голосов
/ 21 января 2009

Единственный другой вариант - делать вручную то, что в любом случае делают многие системы СУБД ...
- Создать новую таблицу

Затем вы можете скопировать содержимое старой таблицы поверх фрагмента за раз. Будучи всегда осторожным в отношении любых INSERT / UPDATE / DELETE в исходной таблице. (Может управляться триггером. Хотя это может привести к замедлению, это не блокировка ...)

По окончании измените имя исходной таблицы, затем измените имя новой таблицы. Желательно в транзакции.

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

EDIT:

Некоторые комментарии были сделаны о том, что это ограничение немного слабое. Так что я подумал, что нужно по-новому взглянуть на это, чтобы показать, почему это так ...

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

  • Вы фактически изменяете физическую структуру на диске, каждая запись перемещается.
  • Это действительно похоже на ОБНОВЛЕНИЕ на всем столе, но с большей отдачей ...
39 голосов
/ 10 октября 2012

Percona создает инструмент под названием pt-online-schema-change , который позволяет это сделать.

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

Это похоже на метод, предложенный Dems выше, но в автоматическом режиме.

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

Ex:

pt-online-schema-change --alter "ADD COLUMN c1 INT" D=db,t=numbers_are_friends
19 голосов
/ 18 июня 2016

Этот вопрос с 2009 года. Теперь MySQL предлагает решение:

онлайн DDL

Функция, улучшающая производительность, параллелизм и доступность. таблиц InnoDB во время операций DDL (прежде всего ALTER TABLE). Увидеть Раздел 14.11, «InnoDB и Online DDL» для получения подробной информации.

Детали могут различаться в зависимости от типа операции. В некоторых случаях, таблица может быть изменена одновременно, пока ALTER TABLE находится в прогресс. Операция может быть выполнена без выполнения копирование таблицы или использование специально оптимизированного типа копирования таблицы. Космос использование контролируется innodb_online_alter_log_max_size опция конфигурации.

Позволяет настроить баланс между производительностью и параллелизмом во время операции DDL, выбирая, следует ли полностью блокировать доступ к таблице (предложение LOCK = EXCLUSIVE), разрешать запросы, но не DML (предложение LOCK = SHARED) или разрешать полное запрос и доступ DML к таблице (предложение LOCK = NONE). Когда вы опускаете предложение LOCK или задаете LOCK = DEFAULT, MySQL разрешает как можно больше параллелизма в зависимости от типа операции.

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

Подробнее см. Справочное руководство по MySQL 5.6 -> InnoDB и Online DDL .

Кажется, что онлайн DDL также доступен в MariaDB

В качестве альтернативы вы можете использовать ALTER ONLINE TABLE, чтобы убедиться, что ваш ALTER TABLE не блокирует параллельные операции (не блокирует). это эквивалентно LOCK = NONE.

MariaDB KB об ALTER TABLE

17 голосов
/ 16 марта 2011

См. Онлайн-инструмент для изменения схемы Facebook.

http://www.facebook.com/notes/mysql-at-facebook/online-schema-change-for-mysql/430801045932

Не для слабонервных; но это сделает работу.

14 голосов
/ 01 июля 2011

Я рекомендую Postgres, если это вариант. В postgres просто нет времени простоя со следующими процедурами:

Другая замечательная особенность заключается в том, что большинство операторов DDL являются транзакционными, поэтому вы можете выполнить полную миграцию внутри транзакции SQL, и, если что-то пойдет не так, все будет отменено.

Я написал это немного назад, возможно, это может пролить немного больше понимания на другие достоинства.

7 голосов
/ 21 января 2009

Поскольку вы спрашивали о других базах данных, вот некоторая информация об Oracle.

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

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

Если вам нужно добавить внешний ключ, вы можете сделать это и заставить Oracle доверять вам, что данные верны. В противном случае необходимо прочитать всю таблицу и проверить все значения, которые могут быть медленными (сначала создайте свой индекс).

Если вам нужно поместить значение по умолчанию или рассчитанное значение в каждую строку нового столбца, вам нужно будет выполнить масштабное обновление или, возможно, небольшую служебную программу, которая заполняет новые данные. Это может быть медленным, особенно если ряды становятся больше и больше не помещаются в свои блоки. Во время этого процесса можно управлять блокировкой. Поскольку старая версия вашего приложения, которая все еще работает, не знает об этом столбце, вам может потребоваться скрытый триггер или указать значение по умолчанию.

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

В качестве альтернативы, вы можете использовать DBMS_REDEFINITION, который представляет собой черный ящик, предназначенный для подобных вещей.

Все это так сложно проверять и т. Д., Что мы просто отключаемся рано утром в воскресенье, когда выпускаем основную версию.

3 голосов
/ 16 мая 2010

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

  • дождаться репликации всех изменений на пассивном подчиненном устройстве
  • изменить пассивного ведомого, чтобы быть активным ведущим
  • сделать структурные изменения для старого мастера
  • копировать изменения обратно от нового мастера к старому мастеру
  • выполнить замену мастера и развертывание нового приложения одновременно

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

2 голосов
/ 21 января 2009

Неа. Если вы используете таблицы MyISAM, то, насколько я понимаю, они только блокируют таблицы - блокировок записей нет, они просто стараются сделать все сверхбыстрым благодаря простоте. (Другие таблицы MySQL работают по-разному.) В любом случае вы можете скопировать таблицу в другую таблицу, изменить ее, а затем переключить их, обновляя для различий.

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

2 голосов
/ 14 августа 2012

Временное решение ...

Другим решением может быть добавление еще одной таблицы с первичным ключом исходной таблицы вместе с вашим новым столбцом.

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

Когда вы можете получить время простоя, вы можете изменить исходную таблицу, изменить ваши запросы DML и удалить новую таблицу, созданную ранее

Иначе, вы можете перейти к методу кластеризации, репликации, pt-online-schema tool от percona

1 голос
/ 25 октября 2016

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

Блог: http://mrafayaleem.com/2016/02/08/live-mysql-schema-changes-with-percona/

...