Что быстрее: несколько одиночных INSERT или один многострочный INSERT?

Я пытаюсь оптимизировать одну часть моего кода, которая вставляет данные в MySQL. Должен ли я подключать INSERT к одному огромному многострочному INSERT или нескольким отдельным INSERT быстрее?

Ответ 1

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

Время, необходимое для вставки строки, определяется следующими факторами, где числа указывают приблизительные пропорции:

  • Подключение: (3)
  • Отправка запроса на сервер: (2)
  • Запрос синтаксического анализа: (2)
  • Вставка строки: (1 × размер строки)
  • Вставка индексов: (1 × количество индексов)
  • Закрытие: (1)

Из этого должно быть очевидно, что отправка одного большого оператора сэкономит вам 7 накладных расходов на оператор вставки, что в дальнейшем чтении текста также говорит:

Если вы вставляете много строк из одного и того же клиента одновременно, используйте операторы INSERT с несколькими списками VALUES для вставки нескольких строк одновременно. Это значительно быстрее (во многих случаях быстрее), чем использование отдельных однострочных операторов INSERT.

Ответ 2

Я знаю, что я отвечаю на этот вопрос почти через два с половиной года после его запроса, но я просто хотел предоставить некоторые жесткие данные из проекта, над которым я сейчас работаю, что показывает, что действительно делает несколько блоков VALUE за вставка МНОГО быстрее, чем последовательные одиночные операторы INSERT блока VALUE.

Код, который я написал для этого теста в С#, использует ODBC для чтения данных в память из источника данных MSSQL (~ 19 000 строк, все считываются до начала записи) и соединителя 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 улучшение становится незначительным.

Надеемся, что люди решат: а) использовать идею multiprepare и (б) сколько блоков VALUE для создания каждого оператора (при условии, что вы хотите работать с данными, которые могут быть достаточно большими, чтобы проталкивать запрос мимо Максимальный размер запроса для MySQL, который, по моему мнению, по умолчанию составляет 16 МБ во многих местах, возможно больше или меньше, в зависимости от значения max_allowed_packet, установленного на сервере.)

Ответ 3

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

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

Если предположить один поток, это означает, что серверу необходимо синхронизировать некоторые данные с диском для КАЖДОЙ РЯДЫ. Он должен дождаться, пока данные достигнут постоянного хранилища (надеюсь, что байт-резервный баран в вашем RAID-контроллере). Это по своей сути довольно медленно и, вероятно, станет ограничивающим фактором в этих случаях.

Я, конечно, предполагаю, что вы используете механизм транзакций (обычно innodb) И что вы не изменили настройки, чтобы уменьшить долговечность.

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

С другой стороны, результатом является то, что вы ДЕЙСТВИТЕЛЬНО ХОТИТЕ ИСПОЛЬЗОВАТЬ многострочные вставки.

Существует предел, по которому он становится контрпродуктивным, но в большинстве случаев он не менее 10 000 строк. Поэтому, если вы заказываете до 1000 строк, вы, вероятно, будете в безопасности.

Если вы используете MyISAM, там есть еще одна нагрузка, но я не буду вас утомлять. Мир.

Ответ 4

Отправить как можно больше вставок по проводу за один раз. Фактическая скорость вставки должна быть одинаковой, но вы увидите прирост производительности от сокращения сетевых издержек.

Ответ 5

В целом, чем меньше вызовов в базе данных, тем лучше (что означает более быстрый, более эффективный), поэтому попробуйте закодировать вставки таким образом, чтобы они минимизировали доступ к базе данных. Помните, что если вы не используете пул соединений, каждый доступ к базам данных должен создать соединение, выполнить sql, а затем разорвать соединение. Немного накладных расходов!

Ответ 6

Вы можете захотеть:

  • Убедитесь, что функция автоматической фиксации отключена.
  • Открыть соединение
  • Отправить несколько пакетов вставок в одной транзакции (размер около 4000-10000 строк), которые вы видите)
  • Закрыть соединение

В зависимости от того, насколько хорошо ваш сервер масштабируется (его окончательно в порядке с PostgreSQl, Oracle и MSSQL), выполните описанную выше вещь с несколькими потоками и несколькими соединениями.

Ответ 7

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

В зависимости от того, какой язык вы используете, вы можете создать партию на языке программирования/сценария перед тем, как перейти к db и добавить каждую вставку в пакет. Тогда вы сможете выполнить большую партию, используя одну операцию подключения. Вот пример в Java.

Ответ 8

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

Я бы сказал, что встроенный способ пойти:)

Ответ 9

Это смешно, насколько плохие Mysql и MariaDB оптимизированы, когда дело доходит до вставок. Я тестировал mysql 5.7 и mariadb 10.3, и никаких реальных отличий от них не было.

Я тестировал это на сервере с дисками NVME, 70 000 IOPS, пропускной способностью 1,1 ГБ/сек и возможностью полного дуплекса (чтение и запись).
Сервер также является высокопроизводительным сервером.
Дал ему 20 ГБ барана.
База данных полностью пуста.

Скорость, которую я получаю, составляла 5000 вставок в секунду при выполнении многострочных вставок (пробовала с 1 МБ до 10 МБ фрагментов данных)

Теперь подсказка:
Если я добавлю еще один поток и вставлю в ТАБЛИЦУШИХ таблиц, у меня вдруг будет 2x5000/сек. Еще один поток, и у меня 15000 всего/сек

Рассмотрим это: при выполнении ONE вставки вставки это означает, что вы можете последовательно записывать на диск (с исключениями для индексов). При использовании потоков вы фактически деградируете возможную производительность, потому что теперь ей нужно делать гораздо более произвольный доступ. Но проверка реальности показывает, что mysql настолько сильно оптимизирован, что потоки очень помогают.

Реальная производительность, возможная с таким сервером, вероятно, составляет миллионы в секунду, процессор находится в режиме ожидания, когда диск простаивает.
Причина в том, что mariadb точно так же, как mysql имеет внутренние задержки.

Ответ 10

несколько вставок быстрее, но это должно быть. Еще один трюк - отключение проверок временных ограничений, делает вставки намного быстрее. Неважно, есть на вашем столе это или нет. Например, проверьте отключение внешних ключей и наслаждайтесь скоростью:

SET FOREIGN_KEY_CHECKS=0;

Конечно, вы должны включить его снова после вставки:

SET FOREIGN_KEY_CHECKS=1;

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

Ответ 11

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