2016-04-11 4 views
3

Предположим, у нас есть 4 таблицы A, B, C, D в Некоторая неопределенная реляционная база данных SQL. Ссылки B, а также C и D. Ссылки означают, что A имеет столбец A.refX_id = X.id, X - A, B и C (общий внешний ключ 1: N).SELECT ... WHERE IN vs JOIN

Что я хочу, это запрос таблицы A с условием на основе столбцов из всех дочерних таблиц B, C и D. Мой вопрос: Какие из следующих вариантов лучше? (. С точки зрения удобства, эффективности, скорости)

Вариант 1:

SELECT DISTINCT A.* FROM A 
    JOIN B ON A.refB_id = B.id 
    JOIN C ON A.refC_id = C.id 
    JOIN D ON A.refD_id = D.id 
    WHERE <condition on B> AND <condition on C> AND <condition on D>; 

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

Вариант 2:

SELECT id FROM B WHERE <condition on B>; # result store to array "BIds" on program side 
SELECT id FROM C WHERE <condition on C>; # result store to array "CIds" on program side 
SELECT id FROM D WHERE <condition on D>; # result store to array "DIds" on program side 

SELECT A.* FROM A 
    WHERE refB_id IN (<B_ids>) AND refC_id IN (<C_ids>) AND refD_id IN (<D_ids>); 

# <B_ids> menas expand whole array of ids, which can result in a very long query string 

Я думал, что Вариант 2 является completelly головня и непригодным для использования с потенциально большими данными. Но я слышал, что многие фреймворки обычно используют его, потому что это относительно просто. Является ли это законным способом запроса таких данных в общем случае, если я знаю, что содержимое предложения «IN» взято из результата другого запроса (-ов)?

+0

просто смотрел этот самый вопрос и нашел этот ответ: http://stackoverflow.com/questions/121631/inner-join-vs-where? rq = 1 – CodeJockey

ответ

3

Я хотел бы призвать вас использовать IN или EXISTS:

SELECT A.* 
FROM A 
WHERE EXISTS (SELECT 1 FROM B WHERE A.refB_id = B.id AND <condition on B>) AND 
     EXISTS (SELECT 1 FROM C WHERE A.refC_id = C.id AND <condition on C>) AND 
     EXISTS (SELECT 1 FROM D WHERE A.refD_id = D.id AND <condition on D>); 

Преимущества такого подхода:

  • Отсутствие опасности получения крупных промежуточных декартовых изделий.
  • Отсутствие расходов на устранение дубликатов для SELECT DISTINCT.
  • Большинство баз данных обрабатывают EXISTS довольно хорошо.
  • Вы можете оптимизировать каждый подзапрос, используя индексы.

EDIT:

Вы можете написать это с IN и подзапросов:

SELECT A.* 
FROM A 
WHERE A.refB_id IN (SELECT B.id FROM B WHERE <condition on B>) AND 
     A.refC_id IN (SELECT C.id FROM C WHERE <condition on C>) AND 
     A.refD_id IN (SELECT D.id FROM D WHERE <condition on D>); 
+0

Спасибо большое! Никогда не видели SELECT 1 ... Как это будет выглядеть с IN? Вы имели в виду это Variant1 ?? – David

+0

Да, это более читаемо. Спасибо, это именно то, что я хотел. – David

+0

@ David Я не согласен с читабельностью, но это зависит от того, что вы привыкли видеть. – CodeJockey

3

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

Кроме того, я хотел бы изменить INNER JOIN к LEFT JOIN при условии, что не все идентификаторы могут соответствовать и переместить WHERE условия JOIN ON условий как

SELECT DISTINCT A.* FROM A 
    LEFT JOIN B ON A.refB_id = B.id AND <condition on B> 
    LEFT JOIN C ON A.refC_id = C.id AND <condition on C> 
    LEFT JOIN D ON A.refD_id = D.id AND <condition on D>; 

 Смежные вопросы

  • Нет связанных вопросов^_^