Оптимизация SQL-запросов с использованием IN over INNER JOIN - PullRequest
3 голосов
/ 12 октября 2011

Дано:

Таблица y

  • id int clustered index
  • name nvarchar(25)

Таблица другого стола

  • id int clustered Index
  • name nvarchar(25)

Таблица someFunction

  • делает некоторые математические вычисления, затем возвращает действительный идентификатор

Сравните:

SELECT y.name
  FROM y
 WHERE dbo.SomeFunction(y.id) IN (SELECT anotherTable.id 
                                    FROM AnotherTable)

против:

SELECT y.name 
  FROM y
  JOIN AnotherTable ON dbo.SomeFunction(y.id) ON anotherTable.id

Вопрос:

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

План выполнения

Ответы [ 3 ]

5 голосов
/ 12 октября 2011

Вообще говоря, IN отличается от JOIN тем, что JOIN может возвращать дополнительные строки, в которых строка имеет более одного совпадения в таблице JOIN.

Из вашей оценкиПлан выполнения, хотя можно видеть, что в этом случае два запроса семантически совпадают

SELECT
        A.Col1
        ,dbo.Foo(A.Col1)
        ,MAX(A.Col2)
        FROM A
        WHERE dbo.Foo(A.Col1)  IN (SELECT Col1 FROM B)
    GROUP BY
        A.Col1,
        dbo.Foo(A.Col1)

против

SELECT
        A.Col1
        ,dbo.Foo(A.Col1)
        ,MAX(A.Col2)
        FROM A
        JOIN B ON dbo.Foo(A.Col1) = B.Col1
    GROUP BY
        A.Col1,
        dbo.Foo(A.Col1)     

Даже если дубликаты вводятся JOIN, тогда они будутудаляется GROUP BY, так как он ссылается только на столбцы из левой таблицы.Кроме того, эти повторяющиеся строки не изменят результат, так как MAX(A.Col2) не изменится.Однако это не относится ко всем агрегатам.Если бы вы использовали SUM(A.Col2) (или AVG или COUNT), то наличие дубликатов изменило бы результат.

Похоже, что SQL Server не имеет никакой логики для различия между агрегатами, такими как MAX, и такими, как SUM, и поэтому вполне возможно, что он расширяет все дубликаты, а затем агрегирует их позже и простовыполнять гораздо больше работы.

Расчетное количество агрегируемых строк составляет 2893.54 для IN против 28271800 для JOIN, но эти оценки не обязательно будут очень надежными, так как предикат объединенияunsargable.

2 голосов
/ 12 октября 2011

Ну, с одной стороны: избавиться от скалярного UDF, который подразумевается под dbo.SomeFunction(y.id). Это действительно убьет вашу производительность .Даже если вы замените его встроенной табличной функцией с одной строкой, это будет лучше.

Что касается вашего фактического вопроса, я нашел аналогичные результаты в других ситуациях и был озадачен подобным образом.Оптимизатор просто относится к ним по-разному;Мне будет интересно посмотреть, какие ответы дают другие.

2 голосов
/ 12 октября 2011

Ваш второй запрос немного забавен - можете ли вы попробовать этот вместо ??

SELECT y.name 
FROM dbo.y
INNER JOIN dbo.AnotherTable a ON a.id = dbo.SomeFunction(y.id) 

Имеет ли это какое-то значение?

В противном случае: посмотрите на планы выполнения! И, возможно, опубликовать их здесь. Не зная намного больше о ваших таблицах (количество и распределение данных и т. Д.) И вашей системе (ОЗУ, диск и т. Д.), Действительно очень трудно дать «глобально» действительное утверждение

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