Як перетворити таблицю рядків 66,862,521 з MyISAM в InnoDB, не виходячи з режиму офлайн протягом декількох годин?


18

чи можна (і як) перетворити величезну таблицю MyISAM в InnoDB, не виймаючи програму в автономному режимі. Для цього потрібно вставляти пару рядків у цю таблицю щосекунди, але можна призупинити її приблизно на 2 хвилини.

Очевидно, ПІСЛЯ ТАБЛИЦІ ... двигун = innodb не працюватиме. Для цього у мене був план створити нову таблицю з двигуном innodb і скопіювати вміст у неї. І врешті-решт, призупиніть потік журналу програми та ОЗНАЙТИ ТАБЛИЦЮ.

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

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



3
Ну, це питання стосується мінімізації часу на розмову. Мені все одно, чи розмова триватиме пару днів чи тижнів. Але він повинен працювати у фоновому режимі, не вимагаючи часу роботи програми та не створюючи помітного відставання.
Гендрік Бруммерманн

Відповіді:


15

Створіть налаштування Master-Master наступним чином:

  • Створіть другий майстер, MasterB
  • MasterB діє як раб logTable
  • Створити logTable_newяк innodb
  • Виконати INSERT INTO logTable_new SELECT * FROM logTable(psuedocode) на MasterB, який надсилає реплікацію на MasterA
  • Коли logTable_newна MasterA закінчується синхронізація, поміняйте місцями таблиці

10

Враховуючи обмеження:

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

Коли ви ведете журнал, якщо у вас є хороший спосіб встановити маркер, щоб ви могли сказати, з чого ви запускаєте процес, щоб потім можна було повторно застосувати будь-які журнали або записати журнали до текстового файлу так пізніше можна їх заковтувати LOAD DATA INFILE

Частина проблеми полягає в тому, що писати меншими партіями означає, що індекси потрібно перераховувати знову і знову; вам краще запустити все це одразу, але це може спричинити деяке «помітне» відставання в системі .. але вам не доведеться робити це на виробничому сервері.

  1. Призупиніть ведення журналу або встановіть якийсь маркер, щоб потім можна було повторно застосувати журнали з цієї точки.
  2. Скопіюйте таблицю MyISM в іншу систему
  3. В іншій системі створіть таблицю InnoDB під іншим іменем та перемістіть дані (можливо, навіть швидше скинути їх та використовувати LOAD DATA INFILE)
  4. Скопіюйте таблицю InnoDB назад у початкову систему
  5. Встановіть інший маркер для ведення журналу.
  6. Повторно застосуйте всі журнали до нової таблиці між двома останніми маркерами.
  7. (повторіть кроки 5 і 6, якщо крок №6 зайняв більше хвилини, до тих пір, поки це не буде лише кілька секунд)
  8. Замініть таблиці (перейменуйте стару на table_BACKUP, нову під іменем старої)
  9. Ловіть журнали з останнього маркера.

9

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

Ви додаєте будь-яку затримку між кожною партією або просто збираєте оновлення та запускаєте кожну партію безпосередньо після попередньої?

Якщо так, то спробуйте створити сценарій конверсії на вашій улюбленій мові чимось на зразок:

repeat
    copy oldest 100 rows that haven't been copied yet to new table
    sleep for as long as that update took
until there are <100 rows unprocessed
stop logging service
move the last few rows
rename tables
restart logging
delete the old table when you are sure the conversion has worked

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

Або якщо ви хочете використати якомога більше часу, коли сервіс відносно не працює, але відключений (потенційно призупиняючи досить тривалий час), коли базі даних потрібно виконати певну роботу для своїх користувачів, замінити sleep for as long as the update tookна if the server's load is above <upper measure>, sleep for some seconds then check again, loop around the sleep/check until the load drops below <lower measure>. Це означає, що він може випереджуватись у тихі часи, але повністю призупиниться, коли сервер зайнятий виконанням нормальної роботи. Визначення навантаження буде залежати від вашої ОС - під Linux та подібним середньозваженим значенням завантаження за 1 хвилину /proc/loadavgабо з результату, який uptimeповинен робити. <lower measure>і це <upper measure>може бути однакове значення, хоча зазвичай у таких елементах управління є різниця, тому ваш процес не продовжується, а відразу призупиняється через його власний перезапуск, який впливає на міру навантаження.

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

Ви захочете ігнорувати звичайну мудрість створення індексів після заповнення нової таблиці в цьому випадку. Хоча це дійсно ефективніше, коли ви хочете, щоб справи пройшли якомога швидше (вплив на решту системи буде проклятим), у цьому випадку ви не хочете, щоб в кінці процесу була велика навантаженість, як індекси створені повністю за один раз, оскільки це процес, який ви не можете призупинити, коли справа зайнята.


4

Чи щось подібне буде працювати?

  1. Призупиніть ведення журналу (щоб $auto_incrementтаблиця в mytable журналі не змінювалася).
  2. Відзначте $auto_incrementзначення, використовуючи SHOW TABLE STATUS LIKE 'mytable'.
  3. CREATE TABLE mytable_new LIKE mytable
  4. ALTER TABLE mytable_new AUTO_INCREMENT=$auto_increment ENGINE=Innodb
  5. RENAME TABLE mytable TO mytable_old, mytable_new TO mytable
  6. Знову ввімкніть журнал. Тепер таблиця Innodb почне заповнюватися.
  7. INSERT INTO mytable SELECT * FROM mytable_old.

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


це все одно буде блокувати через те, що innodb обробляє auto_increment. за замовчуванням innodb приймає блокування рівня таблиці під час вставлення в стовпчик auto_increment та звільняє замок, як тільки вставка закінчена.
ovais.tariq
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.