Почему пакетные вставки / обновления быстрее? Как работают пакетные обновления? - PullRequest
36 голосов
/ 17 июня 2009

Почему пакетные вставки быстрее? Это потому, что затраты на подключение и настройку для вставки одной строки одинаковы для набора строк? Какие еще факторы ускоряют пакетную вставку?

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

Я знаю, что запросы на пакетную вставку имеют синтаксис, в котором у вас есть все значения вставки в одном большом запросе. Как выглядят запросы на пакетное обновление? Например, если у меня есть отдельные запросы на обновление формы:

update <table> set <column>=<expression> where <condition1>
update <table> set <column>=<expression> where <condition2>
update <table> set <column>=<expression> where <condition3>
update <table> set <column>=<expression> where <condition4>

Что происходит, когда они используются в партии. Как будет выглядеть отдельный запрос?

И являются ли пакетные вставки и обновления частью стандарта SQL?

Ответы [ 4 ]

27 голосов
/ 17 июня 2009

Почему пакетные вставки быстрее?

По многим причинам, но основными из них являются:

  • Запрос не нужно повторять.
  • Значения передаются за один прием на сервер
  • Команды находятся внутри одной транзакции

Это потому, что затраты на подключение и настройку для вставки одной строки одинаковы для набора строк?

Частично да, см. Выше.

Как работают пакетные обновления?

Это зависит от RDBMS.

В Oracle вы можете передавать все значения как коллекцию и использовать эту коллекцию как таблицу в JOIN.

В PostgreSQL и MySQL вы можете использовать следующий синтаксис:

INSERT
INTO    mytable
VALUES 
        (value1),
        (value2),
        …

Вы также можете подготовить запрос один раз и вызвать его в каком-то цикле. Обычно есть способы сделать это в клиентской библиотеке.

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

Да, и вы можете или не можете извлечь выгоду из этого поведения.

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

В Oracle вы используете коллекцию в соединении:

MERGE
INTO    mytable
USING   TABLE(:mycol)
ON      …
WHEN MATCHED THEN
UPDATE
SET     …

In PostgreSQL:

UPDATE  mytable
SET     s.s_start = 1
FROM    (
        VALUES
        (value1),
        (value2),
        …
        ) q
WHERE   …
25 голосов
/ 14 января 2013

Я искал ответ на ту же тему об обновлении "навальный / пакетный". Люди часто описывают проблему, сравнивая ее с предложением вставки с несколькими наборами значений («объемная» часть).

INSERT INTO mytable (mykey, mytext, myint)
VALUES 
  (1, 'text1', 11),
  (2, 'text2', 22),
  ...

Четкий ответ все еще избегал меня, но я нашел решение здесь: http://www.postgresql.org/docs/9.1/static/sql-values.html

Чтобы было понятно:

UPDATE mytable
SET 
  mytext = myvalues.mytext,
  myint = myvalues.myint
FROM (
  VALUES
    (1, 'textA', 99),
    (2, 'textB', 88),
    ...
) AS myvalues (mykey, mytext, myint)
WHERE mytable.mykey = myvalues.mykey

Он обладает тем же свойством, что является «объемным», то есть содержит много данных с одним оператором.

4 голосов
/ 26 ноября 2014

Другие посты объясняют, почему массовые операторы быстрее и как это делать с литеральными значениями.

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

Массовая вставка с заполнителями в PostgreSQL> = 9,1

Чтобы вставить произвольное количество строк в таблицу «mytable», состоящую из столбцов «col1», «col2» и «col3», все в одном получено (один оператор, одна транзакция):

INSERT INTO mytable (col1, col2, col3)
 VALUES (unnest(?), unnest(?), unnest(?))

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

Массовое обновление с заполнителями в PostgreSQL> = 9,1

Допустим, ваш стол называется "mytable". Он состоит из столбцов «ключ» и «значение».

update mytable 
  set value = data_table.new_value
  from 
    (select unnest(?) as key, unnest(?) as new_value) as data_table
  where mytable.key = data_table.key

Я знаю, это нелегко понять. Это похоже на запутанный SQL. С другой стороны: он работает, масштабируется, работает без объединения строк, он безопасен и невероятно быстр.

Вам необходимо указать два аргумента для этого утверждения. Первым должен быть список / вектор / массив, содержащий все значения для столбца «ключ». Конечно, второй должен содержать все значения для столбца «значение».

В случае, если вы достигнете предельных размеров, вам, возможно, придется изучить COPY INTO ... FROM STDIN (PostgreSQL).

0 голосов
/ 18 июня 2009

При пакетном обновлении база данных работает с набором данных, при построчном обновлении она должна запускать одну и ту же команду столько раз, сколько существует строк. Таким образом, если вы вставляете миллион строк в пакет, команда отправляется и обрабатывается один раз, а в построчном обновлении она отправляется и обрабатывается миллион раз. Вот почему вы никогда не хотите использовать курсор в SQL Server или коррелированный подзапрос.

пример обновления на основе набора в SQL-сервере:

update mytable
set myfield = 'test'
where myfield is null

Это обновит все 1 миллион записей, которые являются нулевыми за один шаг. Обновление курсора (то есть, как вы обновляете миллион строк не в пакетном режиме) будет перебирать каждую строку по одному и обновлять ее.

Проблема с пакетной вставкой - размер партии. Если вы попытаетесь обновить слишком много записей одновременно, база данных может заблокировать таблицу на время процесса, заблокировав всех остальных пользователей. Таким образом, вам может понадобиться сделать цикл, который принимает только часть пакета за раз (но практически любое число, превышающее одну строку за раз, будет быстрее, чем одна строка за раз). Это медленнее, чем обновление, вставка или удаление весь пакет, но быстрее, чем операции строка за строкой, и может потребоваться в производственной среде с большим количеством пользователей и небольшим временем простоя, когда пользователи не пытаются просматривать и обновлять другие записи в той же таблице. Размер пакета сильно зависит от структуры базы данных и от того, что именно происходит (таблицы с триггерами и множеством ограничений работают медленнее, чем таблицы с большим количеством полей и поэтому требуют меньших пакетов).

...