ALTER TABLE ADD COLUMN занимает много времени

Я просто пытался добавить столбец с названием «местоположение» в таблицу (main_table) в базе данных. Команда, которую я запустил, была

ALTER TABLE main_table ADD COLUMN location varchar (256);

Main_table содержит> 2000000 строк. Он работает более 2 часов и все еще не завершен.

Я пытался использовать mytop для мониторинга активности этой базы данных, чтобы убедиться, что запрос не заблокирован другим процессом запросов, но, похоже, нет. Это должно занять столько времени? На самом деле я просто перезагрузил компьютер перед запуском этой команды. Теперь эта команда все еще выполняется. Я не уверен что делать.


person fanchyna    schedule 29.09.2011    source источник
comment
Это займет много времени из-за индексов и количества строк в таблице. Примечание: Варчар (255)   -  person Jauzsika    schedule 29.09.2011
comment
Думаю, вам следовало указать для него значение по умолчанию. Может поэтому на это нужно время?   -  person Nilesh    schedule 29.09.2011
comment
В этом случае по умолчанию используется NULL, и это определенно не потому, что это занимает много времени.   -  person Romain    schedule 29.09.2011
comment
MySQL 8.0.12 имеет ALTER TABLE .. ADD COLUMN .. ALGORITHM=INSTANT   -  person Rick James    schedule 17.04.2019


Ответы (4)


Ваш оператор ALTER TABLE подразумевает, что mysql придется переписывать каждую строку таблицы, включая новый столбец. Поскольку у вас более 2 миллионов строк, я определенно ожидаю, что это займет значительное время, в течение которого ваш сервер, вероятно, будет в основном привязан к вводу-выводу. Обычно более эффективными являются следующие действия:

CREATE TABLE main_table_new LIKE main_table;
ALTER TABLE main_table_new ADD COLUMN location VARCHAR(256);
INSERT INTO main_table_new SELECT *, NULL FROM main_table;
RENAME TABLE main_table TO main_table_old, main_table_new TO main_table;
DROP TABLE main_table_old;

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

person Romain    schedule 29.09.2011
comment
Стоит отметить @Malvolio: я думаю, что это проприетарное расширение SQL для MySQL ... Не уверен на 100% в этом. - person Romain; 29.09.2011
comment
даже если это так, когда в последний раз кто-либо использовал СУБД SQL, отличную от MySQL? Друзья не позволяют друзьям покупать Oracle. - person Malvolio; 29.09.2011
comment
Спасибо за ваш ответ. Я последовал твоему предложению. Но после того, как я выполню INSERT INTO ... SELECT * FROM ...; команда - person fanchyna; 30.09.2011
comment
Спасибо за ваш ответ. Я последовал твоему предложению. Но после того, как я выполню INSERT INTO ... SELECT * FROM ...; команда более чем за 4 часа, она все еще не закончена. Затем я открываю новый терминал и использую SELECT COUNT (*) из main_table_new; Знаешь что? Я верну 0! Это не записывается в таблицу! Почему? - person fanchyna; 30.09.2011
comment
Может, потому, что темп этой БД недостаточно велик? - person fanchyna; 30.09.2011
comment
@fanchyna Какой движок у стола? Если это транзакция, поддерживающая транзакцию (например, InnoDB), SELECT COUNT(*) FROM main_table_new; вернет 0 до тех пор, пока транзакция INSERT не будет завершена - в зависимости от вашей изоляции транзакции (которая, как я полагаю, по умолчанию равна READ COMMITED) - person Romain; 30.09.2011
comment
Теперь динамическое заполнение fields_in_main_table было бы отличной вещью для использования в скрипте. - person Marki; 08.10.2012
comment
Как добавить блокировку (InnoDB и / или MyISAM)? Как насчет добавления этого: stackoverflow.com/a/5616843/318765 - person mgutt; 22.02.2013
comment
Я выполнил вышеуказанные шаги, но не повезло ... в моей таблице более 10 миллиардов записей - person ni3.net; 17.10.2015
comment
Однако даже этот метод должен переписать всю таблицу. Правильно ли я считаю, что единственное преимущество этого подхода состоит в том, что он позволяет использовать текущую таблицу во время добавления нового столбца? - person Michael; 08.08.2016
comment
Я рекомендую не использовать это решение в реальных производственных базах данных с большим количеством операций записи. Понятно, что в новой таблице могут отсутствовать данные, которые поступают в середине свопа, а также могут произойти длительные блокировки. - person Raul R.; 25.10.2017
comment
Это не поможет вам, если у вас есть внешние ключи, ссылающиеся на таблицу. - person Jonny; 31.10.2017
comment
Вы должны удалить индексы перед командой вставки и воссоздать их после - person Nicolas; 09.06.2018
comment
Будут ли добавлены ограничения, триггеры и индексы для новой таблицы? - person Muhammad Waheed; 29.08.2019
comment
Почему именно добавление столбца приводит к привязке всего сервера к вводу-выводу? - person Shardj; 29.01.2020

Я думаю, что подходящим ответом для этого является использование такой функции, как pt-online-schema-change или gh-ost.

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

Percona работает так же, как указано выше.

  • Создать временную таблицу
  • Создает триггеры в первой таблице (для вставок, обновлений, удалений), чтобы они реплицировались во временную таблицу.
  • Перенос данных небольшими партиями
  • Когда закончите, переименуйте таблицу в новую таблицу и удалите другую таблицу
person Pratik Bothra    schedule 01.11.2016
comment
Это вопрос, свидетельствующий о том, что решение, получившее меньшее количество голосов или принятое, иногда является лучшим или единственно правильным. Сколько людей голосуют за другое неправильное решение, OMG. - person Raul R.; 02.11.2017
comment
@RaulR. Это зависит от варианта использования. Другое решение было достаточно правильным в моем случае использования, не все работают в производственной среде 24/7. - person Austin Schmidt; 24.09.2019
comment
Помните, что изменение схемы pt-online может привести к блокировке таблицы. Если у вашей большой таблицы есть fks, указывающие на нее, вы можете иметь время блокировки или потерять fks. Вам нужно выбрать alter-foreign-keys-method, rebuild_constraints потребуется заново построить fk, который заблокирует ссылочные таблицы. - person Gabriel Furstenheim; 18.01.2021

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

select main_table.*, 
  cast(null as varchar(256)) as null_location, -- any column you want accepts null
  cast('' as varchar(256)) as not_null_location, --any column doesn't accept null
  cast(0 as int) as not_null_int, -- int column doesn't accept null
into new_table 
from main_table;

drop table main_table;
rename table new_table TO main_table;
person ZORRO_BLANCO    schedule 29.03.2018

DB2 z / OS мгновенно виртуально добавляет столбец. И переводит таблицу в статус Advisory-Reorg. Все, что выполняется до реорганизации, получает значение по умолчанию или null, если значение по умолчанию отсутствует. Когда обновления завершены, они расширяют обновленные строки. Вставки делаются развернутыми. Следующая реорганизация расширяет каждую нерасширенную строку и присваивает значение по умолчанию всему, что она расширяет.

Только настоящая база данных справляется с этим хорошо. DB2 z / OS.

person Bill Hulsizer    schedule 16.06.2021
comment
Возможно, вы захотите принять во внимание, что переход на другую базу данных повлечет за собой свои собственные медведи, и что этот ответ не поможет тому, кто задает исходный вопрос, почти через десять лет. - person BertD; 17.06.2021