когда выбрать CROSS APPLY и когда EXISTS?

Я прочитал, ПЕРЕКРЕСТИТЬ ПРИМЕНИТЬ точно так же, как JOIN .. и я думаю, что JOIN также может быть выполнен с EXISTS (коррелированный подзапрос)

Я запутался, в чем разница в использовании CROSS APPLY и EXISTS?

когда мне следует использовать CROSS APPLY против EXISTS?


person dotNETbeginner    schedule 12.03.2012    source источник
comment
Помимо комментариев Гранта, я бы упомянул CROSS APPLY и OUTER APPLY - экзотические операции. Вы можете долгое время выполнять много важной работы, даже не используя APPLY. Не отчаивайтесь узнавать об этом и помнить об этом, но вы обнаружите, что возможности применить APPLY не каждый день. Если вы можете позаимствовать копию TSQL Querying от Itzik Ben-Gan или прочитать несколько страниц в Интернете, у него есть глава под названием TOP и APPLY. Приложения там, я бы сказал, 1) типичные и 2) не очень интересные.   -  person Levin Magruder    schedule 12.03.2012
comment
Да, +10 за книгу Ицика Бен-Гана. Это необходимо.   -  person Grant Fritchey    schedule 12.03.2012
comment
@GrantFritchey: +10? !! обычно люди ставят +1 ..: D;)   -  person dotNETbeginner    schedule 12.03.2012
comment
Когда я пришел сегодня утром, я вспомнил, что коллега только в прошлую пятницу порекомендовал этот ТАК вопрос / ответы на этот связанный, более общий вопрос. Я только просмотрел его, но всего ~ 180 положительных голосов, и мой коллега не может ошибаться.   -  person Levin Magruder    schedule 12.03.2012
comment
@dotNETbeginner Это похоже на выборы в Чикаго: голосуйте раньше и чаще.   -  person Grant Fritchey    schedule 12.03.2012


Ответы (2)


CROSS APPLY - это не просто JOIN. JOIN находит совпадающие (или не совпадающие) строки между двумя наборами данных. CROSS APPLY - это метод выполнения запроса к каждой строке объекта, к которому вы его применяете. Это может действовать как механизм фильтрации, что-то вроде того, как работает JOIN, но он применяет что-то к каждой строке, поэтому об этом нужно думать.

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

Таким образом, хотя вы можете получить одинаковые результаты с помощью этих трех разных методов, используйте их, как определено, и вы обычно будете правы. Если вы буквально соединяете два набора данных, используйте JOIN. Если вы хотите запустить процесс, часто фильтр, для каждой строки в наборе данных, используйте CROSS APPLY. Если вам нужен быстрый фильтр для вероятного положительного совпадения, используйте EXISTS.

person Grant Fritchey    schedule 12.03.2012

Ответ Гранта верен в деньгах. Но с точки зрения личного стиля я использую исключительно OUTER APPLY. Вот общий шаблон, все три из них делают одно и то же, но с помощью внешнего применения при проверке вы можете кратко закомментировать «WHERE ca2.HasAddress = 'Yes'» и добавить ca2.HasAddress в основной выбор, чтобы убедиться, что ваш фильтр удаляет нужные вам записи, в то время как два других метода фильтрации не обеспечивают такой же прозрачности на уровне строк.

SELECT c.CustomerID
FROM SalesLT.Customer c
OUTER APPLY (SELECT TOP 1 'Yes' HasAddress
             FROM SalesLT.CustomerAddress ca
             WHERE c.CustomerID = ca.CustomerID)
             ca2
WHERE ca2.HasAddress = 'Yes'

SELECT c.CustomerID 
FROM SalesLT.Customer c
CROSS APPLY (SELECT TOP 1 'Yes' HasAddress
             FROM SalesLT.CustomerAddress ca
             WHERE c.CustomerID = ca.CustomerID)
             ca2

SELECT c.CustomerID 
FROM SalesLT.Customer c
WHERE EXISTS (SELECT 1
             FROM SalesLT.CustomerAddress ca
             WHERE c.CustomerID = ca.CustomerID)
person Ryan O'Donnell    schedule 21.03.2018
comment
Это то же самое, что и эти два утверждения эквивалентны. ВЫБРАТЬ c.CustomerID ИЗ SalesLT.Customer c ВНУТРЕННЕЕ СОЕДИНЕНИЕ с SalesLT.CustomerAddress ca ON c.CustomerID = ca.CustomerID ВЫБРАТЬ c.CustomerID из SalesLT.Customer c ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ с SalesLT.CustomerAddress camer на c.CustomerID = ca. CustomerID НЕ НУЛЬ - person Ryan O'Donnell; 21.03.2018
comment
Хотя эти два оператора эквивалентны, второй позволяет вам легко проверить данные, просто настроив оператор для этого, чтобы я мог видеть, какие записи удаляются. ВЫБЕРИТЕ c.CustomerID, ca.CustomerID ОТ SalesLT.Customer c ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ с SalesLT.CustomerAddress ca ON c.CustomerID = ca.CustomerID --WHERE ca.CustomerID НЕ НУЛЬ - person Ryan O'Donnell; 21.03.2018