EXISTS vs JOIN и использование предложения EXISTS
Ниже приведен пример кода:
CREATE TABLE #titles(
title_id varchar(20),
title varchar(80) NOT NULL,
type char(12) NOT NULL,
pub_id char(4) NULL,
price money NULL,
advance money NULL,
royalty int NULL,
ytd_sales int NULL,
notes varchar(200) NULL,
pubdate datetime NOT NULL
)
GO
insert #titles values ('1', 'Secrets', 'popular_comp', '1389', $20.00, $8000.00, 10, 4095,'Note 1','06/12/94')
insert #titles values ('2', 'The', 'business', '1389', $19.99, $5000.00, 10, 4095,'Note 2','06/12/91')
insert #titles values ('3', 'Emotional', 'psychology', '0736', $7.99, $4000.00, 10, 3336,'Note 3','06/12/91')
insert #titles values ('4', 'Prolonged', 'psychology', '0736', $19.99, $2000.00, 10, 4072,'Note 4','06/12/91')
insert #titles values ('5', 'With', 'business', '1389', $11.95, $5000.00, 10, 3876,'Note 5','06/09/91')
insert #titles values ('6', 'Valley', 'mod_cook', '0877', $19.99, $0.00, 12, 2032,'Note 6','06/09/91')
insert #titles values ('7', 'Any?', 'trad_cook', '0877', $14.99, $8000.00, 10, 4095,'Note 7','06/12/91')
insert #titles values ('8', 'Fifty', 'trad_cook', '0877', $11.95, $4000.00, 14, 1509,'Note 8','06/12/91')
GO
CREATE TABLE #sales(
stor_id char(4) NOT NULL,
ord_num varchar(20) NOT NULL,
ord_date datetime NOT NULL,
qty smallint NOT NULL,
payterms varchar(12) NOT NULL,
title_id varchar(80)
)
GO
insert #sales values('1', 'QA7442.3', '09/13/94', 75, 'ON Billing','1')
insert #sales values('2', 'D4482', '09/14/94', 10, 'Net 60', '1')
insert #sales values('3', 'N914008', '09/14/94', 20, 'Net 30', '2')
insert #sales values('4', 'N914014', '09/14/94', 25, 'Net 30', '3')
insert #sales values('5', '423LL922', '09/14/94', 15, 'ON Billing','3')
insert #sales values('6', '423LL930', '09/14/94', 10, 'ON Billing','2')
SELECT title, price
FROM #titles
WHERE EXISTS
(SELECT *
FROM #sales
WHERE #sales.title_id = #titles.title_id
AND qty >30)
SELECT t.title, t.price
FROM #titles t
inner join #sales s on t.title_id = s.title_id
where s.qty >30
Я хочу знать, в чем разница между двумя вышеупомянутыми запросами, которые дают одинаковый результат. Также хотим узнать назначение ключевого слова EXISTS и где именно его использовать?
4 ответа
EXISTS
используется для возврата логического значения, JOIN
возвращает другую таблицу
EXISTS
используется только для проверки, если подзапрос возвращает результаты и короткие замыкания, как только это произойдет. JOIN
используется для расширения результирующего набора путем объединения его с дополнительными полями из другой таблицы, к которой существует отношение.
В вашем примере запросы симметрично эквивалентны.
В общем, используйте EXISTS
когда:
- Вам не нужно возвращать данные из связанной таблицы
- У вас есть дубликаты в соответствующей таблице (
JOIN
может вызвать повторяющиеся строки, если значения повторяются) - Вы хотите проверить существование (используйте вместо
LEFT OUTER JOIN...NULL
состояние)
Если у вас есть правильные индексы, большую часть времени EXISTS
будет работать идентично JOIN
, Исключение составляют очень сложные подзапросы, где обычно быстрее использовать EXISTS
,
Если твой JOIN
ключ не индексируется, его можно использовать быстрее EXISTS
но вам нужно будет проверить ваши конкретные обстоятельства.
JOIN
синтаксис также легче читать и понятнее.
- EXISTS является полусоединением
- JOIN - это соединение
Так что с 3 рядами и 5 строками соответствия
- JOIN дает 15 строк
- EXISTS дает 3 ряда
Результатом является эффект "короткого замыкания", упомянутый другими, и нет необходимости использовать DISTINCT с JOIN. EXISTS почти всегда быстрее при поиске существования строк на n стороне отношения 1:n.
EXISTS
в основном используется для ярлыков. По сути, оптимизатор отключится, как только условие будет выполнено, поэтому может не потребоваться сканирование всей таблицы (в современных версиях SQL Server такая оптимизация может происходить для IN()
также хорошо, хотя это не всегда было верно). Это поведение может варьироваться от запроса к запросу, и в некоторых случаях объединение может фактически дать оптимизатору больше возможностей для выполнения своей работы. Поэтому я думаю, что трудно сказать "это когда вы должны использовать EXISTS
и это когда вы не должны "потому что, как и многие вещи", это зависит ".
Тем не менее, в этом случае, поскольку у вас по существу совпадение 1:1 между таблицами, вы вряд ли увидите какую-либо разницу в производительности, и оптимизатор, скорее всего, создаст аналогичный или даже идентичный план. Вы можете увидеть что-то другое, если вы сравните соединение / существует в таблице продаж, когда вы добавляете 50000 строк для каждого заголовка (не говоря уже о том, что вам нужно будет изменить запрос на объединение, чтобы удалить дубликаты, агрегировать, что у вас есть).
Я считаю, что существует, что наиболее полезно, когда у меня есть строки, которые я хотел бы исключить, основываясь на том, как они взаимодействуют с другими строками.
Например,
SELECT *
FROM TABLE a
WHERE a.val IN (1,2,3)
AND NOT EXISTS(SELECT NULL
FROM TABLE b
WHERE b.id = a.id
AND b.val NOT IN (1, 2, 3))
В этом случае я исключаю строку в моем a
запрос основан на наличии b
запись с тем же идентификатором, но недействительная.
Это на самом деле произошло от производственной проблемы, с которой я столкнулся на работе. Запрос переместил большую часть логики исключения в запросе, а не в приложении, что заняло время загрузки от более 24 секунд до менее 2 секунд.:-)