T-SQL: производительность при использовании внутреннего запроса в соединении - PullRequest
1 голос
/ 17 февраля 2011

Вот ситуация, с которой я имею дело. Исходный запрос у меня был:

SELECT c.CustID, a.City, a.Country FROM Customers AS c
    LEFT OUTER JOIN Addresses AS a ON c.CustID = a.CustID
    WHERE c.LastName = 'Jones'

Так что я хотел бы показать всем клиентам с фамилией Джонс, даже без каких-либо адресов, и показать связанные с ними адреса. Но что, если я хочу предложение WHERE по адресам, но все равно показать всех клиентов? Например, если я сделаю это:

SELECT c.CustID, a.City, a.Country FROM Customers AS c
    LEFT OUTER JOIN Addresses AS a ON c.CustID = a.CustID
    WHERE c.LastName = 'Jones' AND a.Country = 'United States'

Я теряю клиентов, которых нет в Соединенных Штатах. Но это не то, что я хочу. Я хочу всех клиентов с фамилией 'Джонс' и пропускаю только адреса , которые не находятся в Соединенных Штатах. Вот решение, которое я придумал:

SELECT  c.CustID, a.City, a.Country FROM Customers AS c
    LEFT OUTER JOIN
        (SELECT City, Country FROM Addresses
        WHERE Country = 'United States') AS a
    ON c.CustID = a.CustID
    WHERE c.LastName = 'Jones'

В этом случае я все еще получаю всех клиентов с фамилией Джонс, но не вижу адресов, которые находятся за пределами США, что я и хотел.

Вот моя проблема: В третьем запросе я предполагаю, что SQL Server выбирает все адреса США, а затем выполняет объединение с таблицей «Клиенты», что означает множество не-Джонс адреса были выбраны без необходимости. Во втором запросе мне интересно, если SQL Server выбирает только адреса США, где LastName = 'Jones', во-первых, что, я думаю, сделает запрос намного быстрее. Так есть ли повышение производительности для второго запроса по сравнению с третьим? Кроме того, какой бы ответ вы ни ответили, не могли бы вы прокомментировать какие-либо различия при использовании внутренних объединений (если они есть), это было бы здорово.

Спасибо!

Ответы [ 5 ]

3 голосов
/ 17 февраля 2011

Выполните тест для страны, являющейся частью условия соединения.

SELECT c.CustID, a.City, a.Country 
    FROM Customers AS c
        LEFT OUTER JOIN Addresses AS a 
            ON c.CustID = a.CustID
                AND a.Country = 'United States'
    WHERE c.LastName = 'Jones'
3 голосов
/ 17 февраля 2011

Вы можете просто добавить свои дополнительные ограничения к своему left join (слово outer здесь избыточно, поскольку все объединения LEFT и RIGHT автоматически OUTER, а все неквалифицированные объединения автоматически INNER ):

SELECT 
    c.CustID, 
    a.City, 
    a.Country 

FROM Customers AS c

LEFT JOIN Addresses AS a ON c.CustID = a.CustID AND a.Country = 'United States'

WHERE c.LastName = 'Jones'

Что касается вашего вопроса о производительности, единственный реальный ответ - выполнить оба запроса и сравнить планы выполнения. При этом синтаксис, основанный исключительно на соединениях, существенно проще и, скорее всего, приведет к более простому (и более быстрому) плану выполнения.

1 голос
/ 16 июля 2011
SELECT c.CustID, a.City, a.Country
  FROM Customers AS c LEFT OUTER JOIN Addresses AS a ON c.CustID = a.CustID
 WHERE c.LastName = 'Jones'
   AND (a.Country = 'United States' OR a.Country IS NULL)
1 голос
/ 17 февраля 2011

Более простая форма вашего запроса будет выглядеть следующим образом:

SELECT c.CustID, a.City, a.Country
FROM Customers AS c     
LEFT OUTER JOIN Addresses AS a 
    ON c.CustID = a.CustID  AND a.Country = 'United States'     
WHERE c.LastName = 'Jones' 

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

Причина, по которой ваш запрос 2 не работает, состоит в том, что, поместив условие в предложение where, вы фактически сделали его внутренним объединением.

0 голосов
/ 21 июня 2012

Пока вы смотрите на производительность, вы можете попробовать оператор APPLY:

SELECT c.CustID, a.City, a.Country  
FROM Customers AS c 
    OUTER APPLY 
    (
        SELECT City, Country
        FROM Addresses  
        WHERE c.CustID = a.CustID 
            AND a.Country = 'United States' 
    ) AS a
WHERE c.LastName = 'Jones'

Иногда, когда таблица справа велика, и оптимизатор считает, что больше 5% илипоэтому записи будут возвращены, вы получите сканирование таблицы и совпадение хеша с внешним соединением.Однако поиск по индексу и вложенный цикл будет быстрее.Я использовал оператор APPLY в некоторых из этих ситуаций, чтобы значительно повысить производительность.

Я не знаю, как это получится в вашем случае, но, возможно, стоит сравнить время выполнения и планы увидетьчто лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...