Створіть індекс на величезній виробничій таблиці MySQL без блокування таблиці


104

Мені потрібно створити індекс у таблиці MySQL ~ 5М рядків. Це виробнича таблиця, і я боюся повного блоку всього, якщо я запускаю CREATE INDEX-заяву ...

Чи є спосіб створити індекс без блокування вставок і вибору?

Цікаво, що я не зупиняюся, створюю індекс і перезавантажую систему!


1
переконайтесь, що розмір myisam_sort_buffer_size та myisam_max_sort_file_size досить великий.
Джон Блек

Відповіді:


130

[2017] Оновлення: MySQL 5.6 підтримує оновлення індексу в Інтернеті

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html#online-ddl-index-syntax-notes

У MySQL 5.6 і новіших версій таблиця залишається доступною для операцій читання і запису під час створення або падіння індексу. Оператор CREATE INDEX або DROP INDEX закінчується лише після завершення всіх транзакцій, які отримують доступ до таблиці, так що початковий стан індексу відображає останній вміст таблиці. Раніше зміна таблиці під час створення або випадання індексу зазвичай призводило до тупикової ситуації, яка скасовувала в таблиці оператор INSERT, UPDATE або DELETE.

[2015] Оновлення блоків індексів таблиці записується в MySQL 5.5

З відповіді вище:

"Якщо ваша версія версії, що перевищує 5,1 індексу, створюється під час роботи бази даних в Інтернеті. Тож не хвилюйтеся, ви не перервете використання виробничої системи."

Це **** FALSE **** (принаймні для таблиць MyISAM / InnoDB, якими користуються 99,999% людей там. Кластерна версія відрізняється.)

Виконання операцій UPDATE на таблиці БЛОКУЄ під час створення індексу. MySQL насправді, дуже дурний щодо цього (та кількох інших речей).

Тестовий сценарій:

(   
  for n in {1..50}; do
    #(time mysql -uroot -e 'select  * from website_development.users where id = 41225\G'>/dev/null) 2>&1 | grep real;
    (time mysql -uroot -e 'update website_development.users set bio="" where id = 41225\G'>/dev/null) 2>&1 | grep real;
  done
) | cat -n &
PID=$!
sleep 0.05
echo "Index Update - START"
mysql -uroot website_development -e 'alter table users add index ddopsonfu (last_name, email, first_name, confirmation_token, current_sign_in_ip);'
echo "Index Update - FINISH"
sleep 0.05
kill $PID
time mysql -uroot website_development -e 'drop index ddopsonfu on users;'

Мій сервер (InnoDB):

Server version: 5.5.25a Source distribution

Вихідні дані (зауважте, як 6-й блок операцій за ~ 400 мс потрібно для завершення оновлення індексу):

 1  real    0m0.009s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.012s
 5  real    0m0.009s
Index Update - START
Index Update - FINISH
 6  real    0m0.388s
 7  real    0m0.009s
 8  real    0m0.009s
 9  real    0m0.009s
10  real    0m0.009s
11  real    0m0.009s

Прочитайте операції, які не блокуються (поміняйте коментар до рядка в сценарії):

 1  real    0m0.010s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.010s
 5  real    0m0.009s
Index Update - START
 6  real    0m0.010s
 7  real    0m0.010s
 8  real    0m0.011s
 9  real    0m0.010s
...
41  real    0m0.009s
42  real    0m0.010s
43  real    0m0.009s
Index Update - FINISH
44  real    0m0.012s
45  real    0m0.009s
46  real    0m0.009s
47  real    0m0.010s
48  real    0m0.009s

Оновлення схеми MySQL без простоїв

Таким чином, існує лише один метод, який я знаю, щоб оновити схему MySql і не зазнати відключення доступності. Майстри кругової галузі:

  • У програмі Master A працює ваша база даних MySQL
  • Принесіть майстра B на службу і повторіть його написання від Master A (B є рабом A)
  • Проведіть оновлення схеми на Master B. Це буде відставати під час оновлення
  • Нехай майстер Б наздожене. Інваріант: Ваша зміна схеми ОБОВ'ЯЗКОВО має бути здатна обробляти команди, реплікувані із схеми зниження рівня. Зміни індексації підлягають визнанню. Прості доповнення до стовпців зазвичай відповідають вимогам. Видалення стовпця? певно, ні.
  • АТОМИЧНО обміняйте всіх клієнтів з Master A на Master B. Якщо ви хочете бути в безпеці (довіртесь, ви це робите), ви повинні переконатися, що останнє записування в A повторюється на B ПЕРЕДБ бере своє перше написання. Якщо ви дозволите одночасне записування для 2+ майстрів, ... ви краще зрозумієте реплікацію MySQL на рівні DEEP або ви прямуєте до світу болю. Сильний біль. Мовляв, чи є у вас стовпець, який є АВТОМОБІЛЬНИМ ??? вас накрутили (якщо ви не використовуєте парних чисел на одному майстрі та коефіцієнтів на іншому). НЕ довіряйте реплікації MySQL "робити все правильно". Це НЕ розумно і не врятує вас. Це просто трохи менш безпечно, ніж копіювати бінарні журнали транзакцій з командного рядка та відтворювати їх вручну. Тим не менш, відключення всіх клієнтів від старого майстра та перехід їх до нового ведучого можна зробити за лічені секунди, набагато швидше, ніж чекати багатогодинного оновлення схеми.
  • Тепер майстер Б - ваш новий господар. У вас є нова схема. Життя чудове. Випити пива; найгірше закінчилося
  • Повторіть процес з Master A, удосконаливши його схему, щоб він став вашим новим вторинним майстром, готовим перейняти його у випадку, якщо ваш основний господар (майстер B зараз) втратить силу або просто вгору і помирає на вас.

Це не простий спосіб оновити схему. Працює у серйозних виробничих умовах; Так. Будь ласка, будь ласка, якщо є більш простий спосіб додати індекс до таблиці MySQL без блокування записів, дайте мені знати.

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

Пер-Пен-онлайн-зміна схем

Статті я пов'язаний вище переговори про інструменті, пт-онлайн-схема заміни , яка працює наступним чином :

  • Створіть нову таблицю з такою ж структурою, як оригінал.
  • Оновлення схеми в новій таблиці.
  • Додайте тригер в оригінальну таблицю, щоб зміни не синхронізувалися з копією
  • Скопіюйте рядки партіями з оригінальної таблиці.
  • Відсуньте оригінальну таблицю з дороги і замініть новою.
  • Відкиньте старий стіл.

Я ніколи не пробував сам інструмент. YMMV

RDS

Зараз я використовую MySQL через RDS Amazon . Це дійсно чудовий сервіс, який завершує та керує MySQL, дозволяючи вам додавати нові репліки для читання за допомогою однієї кнопки та прозоро модернізувати базу даних через апаратні SKU. Це дійсно зручно. Ви не отримуєте SUPER доступу до бази даних, тому ви не можете перекрутити реплікацію безпосередньо (це благо чи прокляття?). Однак ви можете використовувати Просування читання реплік, щоб внести зміни до схеми на підлеглий для читання, а потім просувати цей підлеглий, щоб стати новим господарем. Точно такий же трюк, як я описав вище, просто набагато простіше у виконанні. Вони все ще не дуже допомагають вам у вирішенні. Вам доведеться переналаштувати та перезапустити додаток.


3
pt-он-лайн-зміна схем працює чудово навіть у реплікації ведучого-підлеглого. Я використовував його для живої міграції в напруженій таблиці з читанням 20M + на нашому виробництві master db з двома підлеглими реплікації без жодної ікони чи простоїв. Щоб підготувати сценарій, потрібен певний час, і мені зазвичай доводиться створювати .sql-файл, що містить необмежену зміну SQL та .sh-файл як обгортку, щоб запустити той самий SQL, але у форматі фрагментів (без ALTER TABLE). Ви можете запустити декілька команд за допомогою зміни pt-online-schema, ввівши їх у рядки та розділивши їх комою.
Алекс Ле

-1; Я не знаю про старіші версії, але я знаю, що створення індексу не блокує одночасний DML в MySQL 5.6+ (для якого РК існував на момент написання цієї відповіді і який був офіційно опублікований, коли ця відповідь тривала відредаговано у травні 2013 року), оскільки я покладався на це, щоб запустити багатогодинні створення індексів на виробничих таблицях, все ще приймаючи вставки. І хоча ви можете мати рацію щодо створення індексу, що блокує DML в 5.5 і нижче, продемонстрована тут затримка на другу секунду не зовсім переконлива.
Марк Амері

@MarkAmery - блокування поведінки блокує поведінку, а 400 мс - це вічність. Блоки MySQL 5.5 для оновлення індексу. Створіть більшу тестову базу даних, і вона буде блокуватися протягом секунд, годин або днів. Я написав цю публікацію до того, як MySQL 5.6 оновлював схеми в Інтернеті, тому мій оригінальний вміст не відображає цього факту. Я оновив публікацію, щоб відобразити нещодавно доступну інформацію.
Дейв Допсон

@DaveDopson, ви на 100% впевнені, що блокуються лише операції ОНОВЛЕННЯ?
toto_tico

Так було і для перевіреної мною версії.
Дейв Допсон

67

Як викладається у цьому блозі , InnoDBALTER TABLE механізм був повністю перероблений для MySQL 5.6.

(Для ексклюзивного огляду цієї теми, документація на MySQL може запропонувати прочитати післяобідню годину.)

Щоб додати індекс до таблиці без блокування в результаті UPDATE/ INSERT, можна використовувати такий формат операторів:

ALTER TABLE my_table ADD INDEX my_table__idx (my_column), ALGORITHM=INPLACE, LOCK=NONE;


16

Оновлення MySQL 5.6 (feb 2013): Тепер ви можете виконувати операції читання і запису, поки індекс створюється навіть за таблицями InnoDB - http://dev.mysql.com/doc/refman/5.6/uk/innodb-create-index -overview.html

У MySQL 5.6 і новіших версій таблиця залишається доступною для операцій читання і запису під час створення або падіння індексу. Оператор CREATE INDEX або DROP INDEX закінчується лише після завершення всіх транзакцій, які отримують доступ до таблиці, так що початковий стан індексу відображає останній вміст таблиці. Раніше зміна таблиці під час створення або випадання індексу зазвичай призводило до тупикової ситуації, яка скасовувала в таблиці оператор INSERT, UPDATE або DELETE.

і:

У MySQL 5.6 ця функція стає більш загальною: ви можете читати та записувати в таблиці під час створення індексу, і багато інших видів операцій ALTER TABLE можна виконувати без копіювання таблиці, без блокування операцій DML або обох. Таким чином, у MySQL 5.6 та новіших версіях ми зазвичай називаємо цей набір функцій як Інтернет-DDL, а не швидким створенням індексу.

від http://dev.mysql.com/doc/refman/5.6/uk/glossary.html#glos_fast_index_creation


Тоді як можна пояснити аналіз Дейва?
Нікхіл Саху

1
@NikhilSahu Дейв явно не проводив тестування на MySQL 5.6, але на деяких старих версіях. Зауважте, що 5.6 ще не було опубліковано в той момент, коли Дейв розмістив первинний перегляд своєї відповіді.
Марк Амерді

+1. Мій аналіз був на MySQL 5.5 (останній, який був доступний у 2013 році). Я оновлюю свою відповідь, щоб відобразити нові можливості в MySQL 5.6.
Дейв Допсон

3

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

Як я писав у вищенаведеному коментарі, у мене є декілька досвіду із pt-online-схемою-зміною виробництва. У нас є наша основна таблиця з 20M + записів і головний -> 2 раби-реплікації лише для читання. Я здійснив принаймні десятки міграцій за допомогою pt-online-schema-change - від додавання нового стовпця, зміни діаграми до додавання кількох індексів. Ми також обслуговуємо тонни трафіку під час міграції, і у нас не було жодної гикавки. Звичайно, вам доведеться дуже ретельно протестувати всі сценарії, перш ніж працювати над виробництвом.

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


Я не погоджуюся з вашою беззаперечною рекомендацією від pt-online-schema-change. Це чудово, але є надмірним для багатьох ситуацій, коли інтернет-можливості DDS MySQL 5.6 + вже працюють чудово. Він також має обмеження (як, наприклад, непогана гра з тригерами), і подвоює кількість необхідного запису на вставку до оригінальної таблиці під час зміни схеми. Він обкладе податком ваш диск значно більше, ніж звичайна зміна схеми в Інтернеті, і, таким чином, має потенціал "збити ваш сайт" в тих випадках, коли просто запустивши зміну схеми, простий спосіб спрацював би добре.
Марк Амері

Я писав, грунтуючись на моєму фактичному досвіді зміни pt-online-схем на той час, тому я не впевнений, чому ви назвали мою рекомендацію "некваліфікованою". У нас було щонайменше 1000+ відвідувачів на сайті в будь-який момент, коли я запускав зміни схеми, і, звичайно, дисковий IO оподатковував, але наш сайт не опускався. Добре кешування також допомогло. Я не використовував MySQL 5.6+ онлайн DDL, але, зі свого досвіду, pt-online-схема-зміни зробили свою роботу добре в нашому випадку.
Алекс Ле

1
@AlexYe Yikes, я мав на увазі "некваліфікований" в значенні "без застереження", а не в сенсі "доставлений тим, хто не має права коментувати" - остання інтерпретація не трапилася до мене, поки я не побачив ваш коментар і, звичайно, не не те, що я задумав! тобто я говорив, що, хоча pt-online-schema-changeце корисний інструмент, існує дуже багато ситуацій, коли звичайний онлайн-DDL є настільки ж хорошим і пригоршеним, коли це краще, тому будь-які його рекомендації повинні бути ретельними, а не універсальними.
Марк Амері
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.