Як додати стовпчик до великої таблиці в MySQL


13

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

  1. Змінення таблиці на екрані з блокуванням таблиці. Взяв ~ 30 годин і нічого. Тому я просто зупинив це. По-перше, я помилився, бо не закінчив усі транзакції, але другий раз не було багатоблоків. Статус був copy to tmp table.

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

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

Дякую за будь-який заздалегідь.

Відповіді:


12

Використовуйте MySQL Workbench . Ви можете клацнути правою кнопкою миші таблицю і вибрати "Надіслати в редактор SQL" -> "Створити заяву". Таким чином, жодна таблиця "властивостей" не забудеться додавати (включаючи CHARSETабо COLLATE).
Завдяки цій величезній кількості даних я рекомендую прибрати чи таблицю, або структуру даних, яку ви використовуєте (хороша DBA стане в нагоді). Якщо це неможливо:

  • перейменуйте таблицю ( ALTER) та створіть нову зі CREATEсценарієм, отриманим від Workbench. Ви також можете розширити цей запит за допомогою нового поля, яке вам потрібно
  • BULK ЗАВАНТАЖИТИ дані зі старої таблиці в нову:
    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;

    Таким чином ви уникаєте індексування / тощо для запуску запису за записом. "Оновлення" таблиці все ще буде повільним (оскільки кількість даних величезна), але це найшвидший спосіб, про який я можу придумати.

    EDIT: Прочитайте цю статтю, щоб отримати детальну інформацію про команди, використані у наведеному вище прикладі запиту;)

Мої варіанти чудово. І я отримав SET NAMES utf8і. COLLATIONАле мені IDK чому 30% даних пошкодили після sed. Я думаю, що основне навантаження буде найшвидшим, але, можливо, існує щось більше, чого мені не вистачає. Дякую Марку
ineersa

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

@ineersa сподіваюся, що буде. ви також можете спробувати додати лише частину даних, скажімо, 10% їх, щоб побачити скільки часу потрібно - і мати оцінку для всієї транзакції. Це буде дуже приблизною оцінкою, але все може йти повільно, якщо кеші / пам'ять / все, що заповнюється / перевантажується.

1
Спасибі Марку. Працювало приголомшливо. Навіть швидше, ніж відновити з дампа. Взяв ~ 5 год.
ієерса

5

Ваша ідея sed - це гідний метод, але без помилок чи команди, яку ви виконали, ми не зможемо вам допомогти.

Однак добре відомим способом внесення змін в Інтернет до великих таблиць є pt-online-schema-change . Спрощений огляд того, що робить цей інструмент, скопійовано з документації:

pt-online-schema-change працює, створюючи порожню копію таблиці для зміни, змінюючи її за бажанням, а потім копіюючи рядки з вихідної таблиці в нову таблицю. Коли копія завершена, вона віддаляється від початкової таблиці та замінює її новою. За замовчуванням він також скидає вихідну таблицю.

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


Я спробую групову завантаження пізніше сьогодні ввечері. Якщо він не буде працювати, цей інструмент, ймовірно, знадобиться. Помилки викликані неефективністю деяких символів після використання sed в якості команд. Наприклад 'D\'agostini', викличе помилку unknown command '\''. Але не завжди, як у 30% випадків. Це дивно і баггі. Те саме відбувається навіть із шестигранними сміттєзвалищами. Дякую, Дерек.
ineersa

4

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

Щойно тестував це вчора, маса вставила 70К рядків у таблицю розділів 7 280 К, 10 рядків у кожну секцію, з 5-секундним сном між ними, щоб дозволити іншу пропускну здатність.

Розпочав масові вставки, потім на окремому сеансі запустив онлайн- alterоператор вище в MySQL Workbench, alterготовий до вставлень, два нові стовпці були додані, і жодних рядків не виникла з змін, що означає, що MySQL не копіював жодних рядків.


1
Чому ця відповідь не набирає більше голосів? Це не працює?
fguillen

1

Наразі найкращим варіантом для зміни величезних таблиць є, мабуть, https://github.com/github/gh-ost

gh-ost - безперервне онлайн-рішення для міграції схем для MySQL. Це перевіряється і забезпечує призупиненість, динамічне управління / конфігурацію, аудит та багато оперативних пристрастей.

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

Він був розроблений на основі багаторічного досвіду існуючих рішень та змінює парадигму міграцій таблиць.


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 говорить, що може робити зміни в схемі в Інтернеті, я не встиг зробити їх в Інтернеті для масивних таблиць без блокування суперечка поки що.


-2

у мене просто була та сама проблема. Трохи вирішення:

СТВОРИТИ ТАБЛИЦЮ new_table SELECT * FROM oldtable;

ВИДАЛИТИ З нового_таблиці

ALTER TABLE new_table ADD COLUMN new_column int (11);

ВСТАВЛЯЙТЬСЯ у новий_таблицю вибору *, 0 від старого_таблиці

осінній стіл old_table; перейменувати таблицю new_table TO old_table;


Чому б просто не додати пункт де в оператор створення таблиці, щоб він не вибрав жодних даних? Також обрізання таблиці було б більш ефективним, ніж видалення даних
Joe W

чому видалити, коли доведеться вставити пізніше, знову. Можна визначити за замовчуванням = 0 у ADD COLUMN.
користувач195280
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.