вставка строк из одной таблицы в другую, что является более эффективным (внешнее объединение против последовательного сканирования) - PullRequest
0 голосов
/ 04 декабря 2009

Мне нужно скопировать строки из таблицы B в таблицу A. Требуется только вставить строки, которых еще нет в A.

Мой вопрос: какой из следующих двух более эффективен:

A)

   INSERT INTO A (x, y, z)
   SELECT x, y, z
   FROM B b
   WHERE b.id NOT IN (SELECT id FROM A);

В)

   INSERT INTO A (x, y, z)
   SELECT b.x, b.y, b.z
   FROM B b LEFT OUTER JOIN A a
     ON b.id = a.id
   WHERE a.id is NULL;

Я предполагаю, что ответ зависит от размера таблиц. Но я хотел знать, есть ли что-то явно очевидное в использовании одного подхода над другим.

Чтобы уменьшить неопределенность, допустим, что таблица B будет иметь менее 50 000 строк, а таблица A всегда будет равна или больше по размеру таблице B в 1-5 раз.

Если у кого-нибудь есть другие более эффективные способы сделать это, скажите.

Ответы [ 4 ]

4 голосов
/ 04 декабря 2009

Чтобы добавить еще один параметр:

INSERT INTO A (x, y, z)
SELECT B.x, B.y, B.z
FROM B
WHERE NOT EXISTS(SELECT * FROM A WHERE A.id = B.id)

Я обычно иду с подходом LEFT JOIN. Но если вы хотите точно знать, что наиболее эффективно, запустите несколько тестов в своей среде. Посмотрите, каковы планы выполнения для каждого подхода (вы можете обнаружить, что несколько подходов фактически приводят к одному и тому же плану выполнения).

0 голосов
/ 04 декабря 2009

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

0 голосов
/ 04 декабря 2009

Я думаю, что вариант B лучше, особенно если Таблица A больше, чем Таблица B, с коэффициентом> 1.

Если у вас есть индексы для a.id и b.id, то объединение будет быстрее, ИМХО, чем использование where для каждой строки ...

0 голосов
/ 04 декабря 2009

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

В SQL Server опция A недоступна, если вам нужно присоединиться к кортежу из более чем одного столбца без использования какого-либо обходного метода конкатенации (что я не рекомендую), что приводит нас к варианту C скининга (который я также использую, особенно с соединениями действительно коротко), который распространяется непосредственно на кортежи:

INSERT INTO A (x, y, z) 
SELECT x, y, z 
FROM B b 
WHERE NOT EXISTS (SELECT * FROM A WHERE id = b.id); 

INSERT INTO A (x, y, z) 
SELECT x, y, z 
FROM B b 
WHERE NOT EXISTS (SELECT * FROM A WHERE id1 = b.id1 AND id2 = b.id2); 
...