Как добавить столбец в большую таблицу в MySQL

13

Я разработчик PHP, поэтому не будь строгим. У меня большой дамп таблицы ~ 5,5 ГБ. Наш премьер-министр решил создать в нем новую колонку для выполнения новой функции. Таблица InnoDB, так что я попробовал:

  1. Изменить таблицу на экране с помощью блокировки таблицы. Взял ~ 30 часов и ничего. Так что я просто остановил это. Сначала я ошибся, потому что не завершил все транзакции, но во 2-й раз не было мультиблока. Статус был copy to tmp table.

  2. Поскольку мне также необходимо применить разбиение для этой таблицы, мы решили сделать дамп, переименовать и создать таблицу с тем же именем и новой структурой. Но dump делает строгую копию (по крайней мере, я не нашел что-то еще). Поэтому я добавил, чтобы создать новый столбец sedи запросить его. Но начались странные ошибки. Я считаю, что это было вызвано кодировкой. Таблица в utf-8 и файл стали us-ascii после sed. Поэтому я получил ошибки (неизвестная команда '\' ') на 30% данных. Так что это тоже плохой путь.

Каковы другие варианты для достижения этой цели и повышения производительности (я могу сделать это с помощью PHP-скрипта, но это заняло целую вечность). Каковы будут показатели INSERT SELECTв этом случае.

Спасибо за любое продвижение.

ineersa
источник

Ответы:

12

Используйте MySQL Workbench . Вы можете щелкнуть правой кнопкой мыши таблицу и выбрать «Отправить в редактор SQL» -> «Создать оператор». Таким образом, никакие таблицы «свойств» не будут забыты для добавления (включая CHARSETили COLLATE).
С этим огромным количеством данных я бы порекомендовал очистить используемую вами таблицу или структуру данных (хороший DBA пригодится). Если это невозможно:

  • переименуйте таблицу ( ALTER) и создайте новую с помощью CREATEскрипта, получаемого из Workbench. Вы также можете расширить этот запрос новым нужным вам полем.
  • ЗАГРУЗИТЕ данные из старой таблицы в новую:
    SET FOREIGN_KEY_CHECKS = 0;
    SET UNIQUE_CHECKS = 0;
    SET AUTOCOMMIT = 0;
    INSERT INTO new_table (fieldA, fieldB, fieldC, ..., fieldN)
       SELECT fieldA, fieldB, fieldC, ..., fieldN
       FROM old_table
    SET UNIQUE_CHECKS = 1;
    SET FOREIGN_KEY_CHECKS = 1;
    COMMIT;

    Таким образом, вы избегаете индексирования / etc для запуска записи за записью. «Обновление» таблицы по-прежнему будет медленным (поскольку объем данных огромен), но это самый быстрый способ, который я могу придумать.

    РЕДАКТИРОВАТЬ: прочитайте эту статью, чтобы получить подробную информацию о командах, используемых в приведенном выше примере запроса;)

источник
Мои варианты в порядке. И я получил SET NAMES utf8и. Но мне COLLATIONкажется, почему 30% данных повреждены после sed. Я думаю, что массовая загрузка будет самой быстрой, но, может быть, существует нечто большее, чего мне не хватает. Спасибо Марк
Инерса
1
Повреждение данных в @ineersa может иметь много причин: например, вы открыли файл в редакторе, который не поддерживает все символы, и сохранили его. Или способ, которым вы пытаетесь импортировать из дампа, повреждает данные (он глючит и не может правильно прочитать файл). Или тот же парень может идентифицировать часть некоторых данных как выражение (например, «james \ robin» == «\ r» как выражение) или команду и т. Д. Вот почему я никогда не рекомендую использовать дамп, даже с инструментом дампа двоичных данных только, даже с dev.mysql.com/doc/refman/5.6/en/mysqldump.html (или BCP для MS SQL Server). Слишком много раз он
да, я попробовал с hex-blob. это не помогает Также вы сразу после использования sed mysql идентифицируете \ 'как команду в некоторых именах (не во всех). Это странно и глючит. Попробую массовую загрузку сегодня вечером. Надеюсь, что это будет сделано по крайней мере в 10-15 часов.
Инерса
@ineersa надеюсь, что так и будет. Вы также можете попробовать добавить только часть данных, скажем, 10%, чтобы увидеть, сколько времени это займет - и получить оценку для всей транзакции. Это будет очень грубая оценка, однако, все может пойти медленно, если кеши / память / все, что заполнено / перегружено.
1
Спасибо Марк. Работал потрясающе. Еще быстрее, чем восстанавливать из дампа. Взял ~ 5 часов.
Инерса
5

Ваша идея sed - достойный метод, но без ошибок или команды, которую вы выполнили, мы не сможем вам помочь.

Тем не менее, общеизвестным способом внесения онлайн-изменений в большие таблицы является pt-online-schema-change . Упрощенный обзор того, что делает этот инструмент, скопирован из документации:

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

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

Дерек Дауни
источник
Я попробую массовую загрузку позже сегодня вечером. Если это не сработает, возможно, понадобится этот инструмент. Ошибки вызваны неэффективным отображением некоторых символов после использования sed в качестве команд. Например 'D\'agostini'вызовет ошибку unknown command '\''. Но не всегда, как в 30% случаев. Это странно и глючит. То же самое происходит даже с дампами hex-блобов. Спасибо, Дерек.
Инерса
4

alter table add column, algorithm=inplace, lock=none изменит таблицу MySQL 5.6 без копирования таблицы и без влияния блокировки.

Только что проверил это вчера, массово вставил 70К строк в таблицу разделов 780К строк, по 10К строк в каждый раздел с 5-секундным перерывом в спящем режиме для обеспечения другой пропускной способности.

Запустил массовые вставки, затем в отдельном сеансе запустил онлайн- alterоператор, описанный выше, в MySQL Workbench, alterзавершил до вставок, добавил два новых столбца, и в результате изменения не появилось ни одной строки, означающей, что MySQL не скопировал ни одной строки.

SAK
источник
1
Почему этот ответ не набирает больше голосов? Не работает?
fguillen
1

В настоящее время лучшим вариантом для изменения огромных таблиц является, вероятно, https://github.com/github/gh-ost.

gh-ost - это решение для миграции онлайн-схем без Mygger для MySQL. Он является тестируемым и обеспечивает паузу, динамическое управление / реконфигурацию, аудит и множество преимуществ.

gh-ost создает легкую рабочую нагрузку на главном сервере во время миграции, отделенную от существующей рабочей нагрузки на перенесенной таблице.

Он был разработан на основе многолетнего опыта работы с существующими решениями и изменяет парадигму миграции таблиц.

iJanki
источник
1

Я думаю, что Mydumper / Myloader - хороший инструмент для таких операций: становится лучше с каждым днем. Вы можете использовать свои процессоры и загружать данные параллельно: http://www.percona.com/blog/2014/03/10/new-mydumper-0-6-1-release-offers-several-performance-and- удобство-функции /

Мне удалось загрузить сотни гигабайтных таблиц MySQL за несколько часов.

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

Kubilay
источник
-2

у меня просто была такая же проблема. Небольшое решение:

CREATE TABLE new_table SELECT * FROM oldtable;

УДАЛИТЬ ИЗ new_table

ALTER TABLE new_table ADD COLUMN new_column int (11);

INSERT INTO new_table выберите *, 0 из old_table

удалить таблицу old_table; переименовать таблицу new_table в old_table;

AirCoder
источник
Почему бы просто не добавить предложение where к оператору create table, чтобы оно не выбирало какие-либо данные? Кроме того, усечение таблицы будет более эффективным, чем удаление данных
Joe W
зачем удалять, когда вставлять позже, снова. Можно определить default = 0 в самой ADD COLUMN.
user195280