Відповіді:
https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html
Час, необхідний для вставки рядка, визначається наступними коефіцієнтами, де цифри вказують приблизні пропорції:
- Підключення: (3)
- Надсилання запиту на сервер: (2)
- Розбір запиту: (2)
- Вставка рядка: (1 × розмір рядка)
- Вставка індексів: (1 × кількість індексів)
- Закриття: (1)
З цього повинно бути очевидним, що надсилання одного великого заяви допоможе вам заощадити 7 витрат на оператор-вставок, що в подальшому читанні тексту також говорить:
Якщо ви вставляєте багато рядків з одного клієнта одночасно, використовуйте оператори INSERT з кількома списками VALUES, щоб вставити кілька рядків одночасно. Це значно швидше (у деяких випадках швидше), ніж використання окремих однорядних операторів INSERT.
Я знаю, що я відповідаю на це питання майже через два з половиною роки після того, як його було задано, але я просто хотів надати деякі важкі дані проекту, над яким я зараз працюю, що показує, що дійсно робити декілька VALUE блоків на вкладиш - МНОГО швидше, ніж послідовні оператори INSERT з одним блоком VALUE.
Код, який я написав для цього еталону в C #, використовує ODBC для зчитування даних у пам'яті з джерела даних MSSQL (~ 19000 рядків, всі читаються перед початком запису), а також з'єднувач MySql .NET (Mysql.Data. *) ВСТУПИТИ дані з пам'яті в таблицю на сервері MySQL за допомогою підготовлених операторів. Це було написано таким чином, щоб я міг динамічно регулювати кількість VALUE блоків на підготовлену INSERT (тобто вставляти n рядків за один раз, де я міг би регулювати значення n перед запуском.) Я також провів тест кілька разів для кожного n.
Для виконання окремих блоків VALUE (наприклад, 1 ряд за один раз) потрібно було запустити 5,7 - 5,9 секунди. Інші значення такі:
2 ряди за раз: 3,5 - 3,5 секунди
5 рядків одночасно: 2,2 - 2,2 секунди
10 рядків одночасно: 1,7 - 1,7 секунди
50 рядків одночасно: 1,17 - 1,18 секунди
100 рядків одночасно: 1,1 - 1,4 секунди
500 рядків за один раз: 1,1 - 1,2 секунди
1000 рядків одночасно: 1,17 - 1,17 секунди
Так, так, навіть просто з'єднання 2 або 3 записів разом забезпечує значне поліпшення швидкості (скорочення часу скорочення на коефіцієнт n), поки ви не дістанетесь десь між n = 5 і n = 10, і тоді поліпшення помітно знизиться, а десь у діапазоні n = 10 до n = 50 поліпшення стає незначним.
Сподіваємось, що допоможе людям вирішити (а) чи використовувати ідею для багаторічної підготовки та (б) скільки VALUE блоків для створення оператора (якщо припустити, що ви хочете працювати з даними, які можуть бути досить великими, щоб підштовхнути запит повз максимальний розмір запиту для MySQL, який, на мою думку, становить 16 Мб за замовчуванням у багатьох місцях, можливо, більший чи менший залежно від значення max_allowed_packet, встановленого на сервері.)
Основним фактором буде те, чи використовуєте ви транзакційний двигун та чи увімкнено автокомісію.
Автокомісія включена за замовчуванням, і ви, ймовірно, хочете залишити її; тому кожна вставка, яку ви робите, робить свою власну транзакцію. Це означає, що якщо ви робите по одній вставці в рядку, ви збираєтесь здійснювати транзакцію для кожного рядка.
Якщо припустити єдиний потік, це означає, що серверу потрібно синхронізувати деякі дані для диска для ВСЕ РЯДОГО. Потрібно чекати, коли дані дістануть постійного місця зберігання (сподіваємось, що баран, що підтримується батареєю, у вашому RAID-контролері). Це по суті досить повільно і, ймовірно, стане обмежуючим фактором у цих випадках.
Звичайно, я припускаю, що ви використовуєте транзакційний двигун (як правило, innodb) І що ви не змінили налаштування, щоб зменшити довговічність.
Я також припускаю, що ви використовуєте одну нитку, щоб зробити ці вставки. Використання декількох потоків дещо замутніло, оскільки деякі версії MySQL мають робочу групу-фіксування в innodb - це означає, що кілька потоків, виконуючи свої власні зобов’язання, можуть ділитися одним записом до журналу транзакцій, що добре, оскільки означає менше синхронізації для постійного зберігання .
З іншого боку, підсумок полягає в тому, що ви дійсно хочете використовувати багаторядкові вставки.
Існує межа, над якою вона отримує контрпродуктивність, але в більшості випадків це не менше 10 000 рядів. Тож якщо ви будете купувати їх до 1000 рядів, ви, ймовірно, в безпеці.
Якщо ви використовуєте MyISAM, є ще цілий ряд речей, але я вам не набридаю. Мир.
Загалом, чим менше кількість дзвінків до бази даних, тим краще (мається на увазі швидше, ефективніше), тому намагайтеся кодувати вставки таким чином, щоб це мінімізувало доступ до бази даних. Пам'ятайте, якщо ви не використовуєте пул з'єднань, кожен доступ до бази даних повинен створити з'єднання, виконати sql та розірвати з'єднання. Зовсім трохи накладних!
Ви можете:
Залежно від того, наскільки добре масштабується ваш сервер (його остаточно гаразд із PostgreSQl
, Oracle
і MSSQL
), виконайте це вище за допомогою декількох потоків та декількох з'єднань.
Загалом, кілька вставок будуть повільнішими через накладні з'єднання. Виконання декількох вставок одночасно знизить витрати на накладні витрати на одну вставку.
Залежно від того, якою мовою ви користуєтесь, ви, можливо, можете створити пакет у мові програмування / сценаріїв перед тим, як перейти до db та додати кожну вставку до групи. Тоді ви зможете виконати велику партію за допомогою однієї операції підключення. Ось приклад на Java.
MYSQL 5.5 Один оператор вставлення sql займав від 300 до ~ 450 мс. тоді як наведена нижче статистика призначена для вбудованих декількох вставок.
(25492 row(s) affected)
Execution Time : 00:00:03:343
Transfer Time : 00:00:00:000
Total Time : 00:00:03:343
Я б сказав, що в інтернеті - це шлях :)
Смішно, наскільки погано оптимізовано Mysql та MariaDB, якщо мова йде про вставки. Я перевірив mysql 5.7 та mariadb 10.3, різниці в цьому немає.
Я перевірив це на сервері з дисками NVME, 70 000 IOPS, пропускною здатністю 1,1 ГБ / с, і це можливо повний дуплекс (читання та запис).
Сервер також є високопродуктивним сервером.
Дав йому 20 ГБ оперативної пам’яті.
База даних повністю порожня.
Швидкість, яку я отримував, становила 5000 вставок в секунду, коли робила кілька рядкових вставок (спробувала це з 1 Мб до 10 МБ фрагментів даних)
Тепер підказка:
Якщо я додаю ще одну нитку і вставляю в таблиці SAME, я раптом маю 2x5000 / сек. Ще одна нитка, і я маю 15000 всього / сек
Враховуйте це: Коли ви робите ONE вставлення потоку, це означає, що ви можете послідовно записувати на диск (за винятком індексів). Використовуючи теми, ви фактично погіршуєте можливу ефективність, тому що зараз їй потрібно зробити набагато більше випадкових доступів. Але перевірка реальності показує, що mysql настільки погано оптимізований, що теми дуже допомагають.
Реальна продуктивність, можлива на такому сервері, мабуть, мільйони в секунду, процесор простоює, диск - в режимі очікування.
Причина досить чітка в тому, що mariadb так само, як і mysql, має внутрішні затримки.
id
, parent_id
) ЦІННОСТІ (1, NULL). Один з наступних наборів значень посилається на цей рядок. Якщо ви розділите шматки, і цей набір потрапить на інший фрагмент, він може бути оброблений до першого, не вдавшись до всього процесу. Будь-яка ідея, як з цим боротися?
кілька вставок швидше, але це повинно було пропустити. ще один трік - відключення обмежень, перевірки тимчасових вставень набагато швидше. Це не має значення, він має його чи ні. Наприклад, перевірити відключення сторонніх ключів і насолоджуватися швидкістю:
SET FOREIGN_KEY_CHECKS=0;
Вихід слід включити після вставки:
SET FOREIGN_KEY_CHECKS=1;
це звичайний спосіб вставлення величезних даних. цілісність даних може порушитися, тому ви повинні подбати про це перед відключенням перевірки зовнішніх ключів.