Що швидше: кілька одиночних ВСТУП або одна багаторядкова ВСТАВКА?


184

Я намагаюся оптимізувати одну частину свого коду, яка вставляє дані в MySQL. Чи варто ланцюжком INSERT, щоб зробити одну величезну багаторядкову ВСТУП чи швидше зробити декілька окремих ВСТУП?

Відповіді:


287

https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html

Час, необхідний для вставки рядка, визначається наступними коефіцієнтами, де цифри вказують приблизні пропорції:

  • Підключення: (3)
  • Надсилання запиту на сервер: (2)
  • Розбір запиту: (2)
  • Вставка рядка: (1 × розмір рядка)
  • Вставка індексів: (1 × кількість індексів)
  • Закриття: (1)

З цього повинно бути очевидним, що надсилання одного великого заяви допоможе вам заощадити 7 витрат на оператор-вставок, що в подальшому читанні тексту також говорить:

Якщо ви вставляєте багато рядків з одного клієнта одночасно, використовуйте оператори INSERT з кількома списками VALUES, щоб вставити кілька рядків одночасно. Це значно швидше (у деяких випадках швидше), ніж використання окремих однорядних операторів INSERT.


27
Як ця відповідь застосовується, якщо в одній транзакції з базою даних є кілька одиночних INSERT?
Пінч

2
Скільки рядків я можу вставити за один раз за допомогою одного оператора вставки. чи дозволяєте мені вставляти 10000 рядків одночасно?
Нареш Рамолія

10
@Pinch Використання транзакції під час виконання ~ 1,5k оновлень (вставка / оновлення) скоротило час операції з ~ 1,5 секунди до ~ 0,2 секунди. Або іншими словами, це зробило це на 86% швидше порівняно з однорядними вставками. Блін.
fgblomqvist

1
Примітка: Здається , буде сильно відрізнятися в MSSQL: stackoverflow.com/questions/8635818 / ...
marsze

Як щодо використання підготовленої заяви для вставки повторюваних кількох одиночних вставок?
priyabagus

151

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


1
Запит на уточнення: ваш час "секунд на рядок" або "всього секунд".
EngrStudent

3
Всього секунд - значить, секунди на ряд - це поділене на ~ 19 000 рядків. Хоча це невелика кількість, тому, можливо, рядки / секунди є кращим показником, якщо ви шукаєте легко порівнянне число.
Джон Клоське,

До речі, є кілька прикладів , .NET коду для підходу я описую вище на цьому пов'язаний відповідь мій: stackoverflow.com/questions/25377357 / ...
Джон Kloske

18

Основним фактором буде те, чи використовуєте ви транзакційний двигун та чи увімкнено автокомісію.

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

Якщо припустити єдиний потік, це означає, що серверу потрібно синхронізувати деякі дані для диска для ВСЕ РЯДОГО. Потрібно чекати, коли дані дістануть постійного місця зберігання (сподіваємось, що баран, що підтримується батареєю, у вашому RAID-контролері). Це по суті досить повільно і, ймовірно, стане обмежуючим фактором у цих випадках.

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

Я також припускаю, що ви використовуєте одну нитку, щоб зробити ці вставки. Використання декількох потоків дещо замутніло, оскільки деякі версії MySQL мають робочу групу-фіксування в innodb - це означає, що кілька потоків, виконуючи свої власні зобов’язання, можуть ділитися одним записом до журналу транзакцій, що добре, оскільки означає менше синхронізації для постійного зберігання .

З іншого боку, підсумок полягає в тому, що ви дійсно хочете використовувати багаторядкові вставки.

Існує межа, над якою вона отримує контрпродуктивність, але в більшості випадків це не менше 10 000 рядів. Тож якщо ви будете купувати їх до 1000 рядів, ви, ймовірно, в безпеці.

Якщо ви використовуєте MyISAM, є ще цілий ряд речей, але я вам не набридаю. Мир.


1
Чи є якась причина, що вона стає протипродуктивною після точки? Я бачив це і раніше, але не знав, чому.
Друв Гайрола

1
Чи знаєте ви, чи є взагалі якийсь момент в пакетному вкладенні MySQL при використанні транзакцій . Мені просто цікаво, чи можу я врятувати собі проблему з необхідністю генерувати багатозначну команду SQL, якщо моя основна бібліотека (Java JDBC - mysql-connector-java-5.1.30) насправді не виконує, поки я не скажу про це.
RTF

@RTF Я думаю, що вам потрібно буде провести невеликий тест, щоб визначити, що така поведінка у вашій ситуації, оскільки це дуже специфічна поведінка, але у багатьох випадках так, транзакції повинні забезпечити аналогічні результативність.
Жасмін Гегман

9

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


7

Загалом, чим менше кількість дзвінків до бази даних, тим краще (мається на увазі швидше, ефективніше), тому намагайтеся кодувати вставки таким чином, щоб це мінімізувало доступ до бази даних. Пам'ятайте, якщо ви не використовуєте пул з'єднань, кожен доступ до бази даних повинен створити з'єднання, виконати sql та розірвати з'єднання. Зовсім трохи накладних!


що робити, якщо використовується стійке з'єднання?
сутінки

6
Є ще накладні витрати. Один час транзиту (до та з кожної окремої вставки) буде швидко відчутний, якщо ви робите тисячі вставок.
RC.

4

Ви можете:

  • Переконайтеся, що автоматичне фіксація вимкнено
  • Відкрите з'єднання
  • Надішліть декілька партій вставок за одну транзакцію (розмір близько 4000-10000 рядків? Ви бачите)
  • Тісне з'єднання

Залежно від того, наскільки добре масштабується ваш сервер (його остаточно гаразд із PostgreSQl, Oracleі MSSQL), виконайте це вище за допомогою декількох потоків та декількох з'єднань.


3

Загалом, кілька вставок будуть повільнішими через накладні з'єднання. Виконання декількох вставок одночасно знизить витрати на накладні витрати на одну вставку.

Залежно від того, якою мовою ви користуєтесь, ви, можливо, можете створити пакет у мові програмування / сценаріїв перед тим, як перейти до db та додати кожну вставку до групи. Тоді ви зможете виконати велику партію за допомогою однієї операції підключення. Ось приклад на Java.


3

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

Я б сказав, що в інтернеті - це шлях :)


0

Смішно, наскільки погано оптимізовано 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, має внутрішні затримки.


@Craftables вам потрібна зовнішня розробка, це неможливо зробити в межах mysql. Нитки означають, що ви використовуєте кілька підключень до сервера, ви розділяєте запит на кілька фрагментів (наприклад, розділивши його на рівні частини за допомогою первинного ключа). Мені вдалося отримати в 10 000 разів продуктивність за допомогою цього методу на дуже великих таблицях. Запити, які запускаються 40 000 секунд, можуть закінчитися за 2-3 хвилини, якщо ви використовуєте кілька потоків, і ваш mysql дуже оптимізований.
Іван

@John Цікаво і, можливо, є справжні приємні програми ... але ... Якщо ви розділите запит на кілька фрагментів, як ви обробляєте транзакції? А також врахуйте наступний сценарій: У таблиці x є стовпець 'parent_id', який відноситься до тієї ж таблиці 'id'. Десь усередині ваших даних є ВСТАВЛЕННЯ В Х ( id, parent_id) ЦІННОСТІ (1, NULL). Один з наступних наборів значень посилається на цей рядок. Якщо ви розділите шматки, і цей набір потрапить на інший фрагмент, він може бути оброблений до першого, не вдавшись до всього процесу. Будь-яка ідея, як з цим боротися?
ZoZo

@zozo це корисно для масових вставок і масових запитів. Операції в будь-якому разі зруйнують ефективність, оскільки вони включають велику кількість буферизації даних. Але ви також можете використовувати транзакції в багатопотокових вставках або запитах.
Іван

-2

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

SET FOREIGN_KEY_CHECKS=0;

Вихід слід включити після вставки:

SET FOREIGN_KEY_CHECKS=1;

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


1
Не маю уявлення, чому ppl підтримує це з двох причин: 1. Це не має нічого спільного з питанням 2. Це дійсно погана ідея (за кількома винятками - як демпінг або зміни структурних темпів -, але загалом погана). Чеки існують з причини: вони є там, щоб забезпечити узгодженість даних. Вони сповільнюють ситуацію через те, що вони гарантують, що ви не вставляєте чи іншим чином змінюєте дані, які не повинні. Спробуйте оптимізувати запити правильним способом; у будь-якому критичному для бізнесу середовищі це означатиме загибель програми, оскільки незалежно від того, наскільки обережно ви ставитесь, в якийсь момент не вдасться.
ZoZo

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