SQL JOIN с двумя или более таблицами в качестве вывода - самый эффективный способ? - PullRequest
2 голосов
/ 06 мая 2010

У меня есть SQL-запрос, который выполняет LEFT JOIN для другой таблицы, а затем выводит все результаты, которые могут быть связаны в назначенную таблицу. Затем у меня есть второй запрос SQL, который снова выполняет LEFT JOIN, а затем выводит результаты, которые не могут быть связаны с указанной таблицей. В коде это что-то вроде:

INSERT INTO coupledrecords
SELECT b.col1, b.col2... s.col1, s.col2... FROM bigtable AS b
LEFT JOIN smallertable AS s
ON criterium
WHERE s.col1 IS NOT NULL

INSERT INTO notcoupledrecords
SELECT b.col1, b.col2... bigtable AS b
LEFT JOIN smallertable AS s
ON criterium
WHERE s.col1 IS NULL

Мой вопрос: теперь мне нужно выполнить JOIN два раза, чтобы достичь того, чего я хочу. У меня такое ощущение, что это вдвое медленнее, чем могло бы быть. Это правда, и если да, есть ли способ сделать это более эффективно?

Ответы [ 5 ]

4 голосов
/ 06 мая 2010

Если вы вставляете разные результаты в 2 разные таблицы, вам понадобятся 2 разных запроса.

Единственное, что я хотел бы предложить, это то, что запрос «связанных записей» может быть просто ВНУТРЕННИМ СОЕДИНЕНИЕМ:

INSERT INTO coupledrecords
SELECT b.col1, b.col2... s.col1, s.col2... FROM bigtable AS b
INNER JOIN smallertable AS s 
ON criterium

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

3 голосов
/ 06 мая 2010

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

INSERT INTO coupledrecordsView
SELECT case WHEN s.col1 IS NULL THEN 1 ELSE 0 END AS IsCoupled,
b.col1, b.col2... s.col1, s.col2... FROM bigtable AS b
LEFT JOIN smallertable AS s
ON criterium
3 голосов
/ 06 мая 2010

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

2 голосов
/ 06 мая 2010

Если вы можете изменить кластеризованные индексы coupledrecords и notcoupledrecords, чтобы они содержали один столбец из smalltable (включая привязку вычисляемого битового столбца в конце каждого кластеризованного индекса, исключительно для этой цели - см. Ответ @Martin Smith выше), тогда вы можете использовать Partitioned View для вставки. Это простая возможность.

Если это невозможно, вы также можете попробовать решение без разделов. Смотрите ниже - это более запутанно.

Не зная, как распределяются ваши данные (например, размер строки, число столбцов, которые можно обнулять или не обнулять, отношение связанных и не связанных), трудно порекомендовать общее решение, но одно решение, которое может работать хорошо в большинстве случаев, это использовать представления для имитации связанных и несвязанных таблиц поверх одной таблицы "maybecoupled". Использование представлений означает, что ваш существующий код запроса (кроме вставки) не нужно будет менять.

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

Вот как это будет работать:

  • INSERT все записей в базовой таблице (например, maybecoupled) за один проход
  • Убедитесь, что в одном из столбцов, полученных из smalltable, есть индекс (в идеале, кластеризованный, но и некластеризованный). Давайте предположим, что это indexedcol1
  • Создайте два представления сверху: coupledrecords и notcoupledrecords, определения которых SELECT col1, ... FROM maybecoupled WHERE indexedcol1 IS NULL и SELECT col1, ... FROM maybecoupled WHERE indexedcol1 IS NOT NULL.
  • если у вас есть кластеризованный индекс для indexedcol1, то вы будете платить минимальные или нулевые штрафы за большинство запросов, поскольку каждый запрос в любом представлении будет попадать только в соответствующую половину записей и никогда не затрагивать другую половину. Ваши некластеризованные индексы станут немного больше и, следовательно, немного медленнее, но даже это можно улучшить с помощью отфильтрованных индексов .
  • если вы не можете использовать кластеризованный индекс, убедитесь, что indexcol1 является частью (или INCLUDE-d в) каждого некластеризованного индекса. Это предотвращает необходимость возврата к кластерному индексу для поиска indexcol1 для запросов, которые извлекают данные только из некластеризованных индексов.

Вот несколько случаев, когда вышеуказанное решение не будет работать:

  • , если число связанных строк относительно невелико и у вас либо много необнуляемых столбцов в bigtable, либо у вас очень маленькие строки. Тогда пространство над всеми этими несвязанными рядами может пострадать. (пустые значения не занимают места, но столбцы, не имеющие значения NULL).
  • если вы используете некластеризованный indexcol1 и не можете изменить ваши индексы, чтобы обеспечить наличие indexcol1 в ваших некластеризованных индексах
  • если вышеуказанные махинации приводят к тому, что SQL Server выбирает неправильные индексы для использования в планах запросов из-за повышенной сложности запросов (хотя это можно исправить с помощью подсказок по индексам)

Предостережение: вы определенно захотите протестировать производительность любого солютона на основе представлений, чтобы убедиться, что он не ухудшает ситуацию - SQL обычно хорош при выборе хороших планов запросов, но не всегда. Тест, Тест, Тест!

0 голосов
/ 06 мая 2010

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

INSERT INTO notcoupledrecords
SELECT b.col1, b.col2... bigtable AS b
WHERE some_col not in (select some_col from coupledrecords) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...