Какой SQL-запрос быстрее? Фильтр на критериях Соединения или операторе Where?

Сравните эти 2 запроса. Это быстрее для помещения фильтра на критерии соединения, или в был пункт. Я всегда чувствовал, что это быстрее на критериях соединения, потому что это уменьшает набор результатов в как можно скорее возможный момент, но я не знаю наверняка.

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

Запрос 1

SELECT      *
FROM        TableA a
INNER JOIN  TableXRef x
        ON  a.ID = x.TableAID
INNER JOIN  TableB b
        ON  x.TableBID = b.ID
WHERE       a.ID = 1            /* <-- Filter here? */

Запрос 2

SELECT      *
FROM        TableA a
INNER JOIN  TableXRef x
        ON  a.ID = x.TableAID
        AND a.ID = 1            /* <-- Or filter here? */
INNER JOIN  TableB b
        ON  x.TableBID = b.ID

Править

Я запустил некоторые тесты, и результаты показывают, что это на самом деле очень близко, но WHERE пункт на самом деле немного быстрее!=)

Я абсолютно соглашаюсь, что имеет больше смысла применять фильтр на WHERE пункт, мне было просто любопытно относительно последствий производительности.

ПРОШЕДШЕЕ ВРЕМЯ, ГДЕ КРИТЕРИИ: 143 016 мс
КРИТЕРИИ СОЕДИНЕНИЯ ПРОШЕДШЕГО ВРЕМЕНИ: 143 256 мс

ТЕСТ

SET NOCOUNT ON;

DECLARE @num    INT,
        @iter   INT

SELECT  @num    = 1000, -- Number of records in TableA and TableB, the cross table is populated with a CROSS JOIN from A to B
        @iter   = 1000  -- Number of select iterations to perform

DECLARE @a TABLE (
        id INT
)

DECLARE @b TABLE (
        id INT
)

DECLARE @x TABLE (
        aid INT,
        bid INT
)

DECLARE @num_curr INT
SELECT  @num_curr = 1

WHILE (@num_curr <= @num)
BEGIN
    INSERT @a (id) SELECT @num_curr
    INSERT @b (id) SELECT @num_curr

    SELECT @num_curr = @num_curr + 1
END

INSERT      @x (aid, bid)
SELECT      a.id,
            b.id
FROM        @a a
CROSS JOIN  @b b

/*
    TEST
*/
DECLARE @begin_where    DATETIME,
        @end_where      DATETIME,
        @count_where    INT,
        @begin_join     DATETIME,
        @end_join       DATETIME,
        @count_join     INT,
        @curr           INT,
        @aid            INT

DECLARE @temp TABLE (
        curr    INT,
        aid     INT,
        bid     INT
)

DELETE FROM @temp

SELECT  @curr   = 0,
        @aid    = 50

SELECT  @begin_where = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
    INSERT      @temp (curr, aid, bid)
    SELECT      @curr,
                aid,
                bid
    FROM        @a a
    INNER JOIN  @x x
            ON  a.id = x.aid
    INNER JOIN  @b b
            ON  x.bid = b.id
    WHERE       a.id = @aid

    SELECT @curr = @curr + 1
END
SELECT  @end_where = CURRENT_TIMESTAMP

SELECT  @count_where = COUNT(1) FROM @temp
DELETE FROM @temp

SELECT  @curr = 0
SELECT  @begin_join = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
    INSERT      @temp (curr, aid, bid)
    SELECT      @curr,
                aid,
                bid
    FROM        @a a
    INNER JOIN  @x x
            ON  a.id = x.aid
            AND a.id = @aid
    INNER JOIN  @b b
            ON  x.bid = b.id

    SELECT @curr = @curr + 1
END
SELECT  @end_join = CURRENT_TIMESTAMP

SELECT  @count_join = COUNT(1) FROM @temp
DELETE FROM @temp

SELECT  @count_where AS count_where,
        @count_join AS count_join,
        DATEDIFF(millisecond, @begin_where, @end_where) AS elapsed_where,
        DATEDIFF(millisecond, @begin_join, @end_join) AS elapsed_join
83
задан gbn 4 May 2010 в 04:47
поделиться

8 ответов

С точки зрения производительности они одинаковы (и выдают одинаковые планы)

С точки зрения логики, вы должны сделать операцию, которая все еще имеет смысл, если заменить INNER JOIN на LEFT JOIN.

В вашем случае это будет выглядеть так:

SELECT  *
FROM    TableA a
LEFT JOIN
        TableXRef x
ON      x.TableAID = a.ID
        AND a.ID = 1
LEFT JOIN
        TableB b
ON      x.TableBID = b.ID

или так:

SELECT  *
FROM    TableA a
LEFT JOIN
        TableXRef x
ON      x.TableAID = a.ID
LEFT JOIN
        TableB b
ON      b.id = x.TableBID
WHERE   a.id = 1

Первый запрос не вернет никаких фактических совпадений для a.id, кроме 1, поэтому второй синтаксис (с WHERE) логически более последовательный.

58
ответ дан 24 November 2019 в 08:56
поделиться

Для внутренних объединений не имеет значения, где вы помещаете свои критерии. Компилятор SQL преобразует оба в план выполнения, в котором фильтрация происходит ниже соединения (т. Е. Как если бы выражения фильтра появлялись в условии соединения).

Внешние соединения - это другое дело, поскольку место фильтра меняет семантику запроса.

19
ответ дан 24 November 2019 в 08:56
поделиться

Что касается двух методов.

  • JOIN / ON для объединения таблиц
  • WHERE для фильтрации результатов

Хотя вы можете использовать их по-разному, мне всегда кажется, что это запах.

Работайте с производительностью, когда это проблема. Тогда вы можете изучить такие «оптимизации».

8
ответ дан 24 November 2019 в 08:56
поделиться

На самом деле маловероятно, что размещение этого соединения будет решающим фактором для производительности. Я не очень хорошо знаком с планированием выполнения tsql, но вполне вероятно, что они будут автоматически оптимизированы для аналогичных планов.

0
ответ дан 24 November 2019 в 08:56
поделиться

Правило № 0: Проведите несколько тестов и посмотрите! Единственный способ действительно сказать, что будет быстрее, - это попробовать. Эти типы тестов очень легко выполнить с помощью профилировщика SQL.

Также изучите план выполнения запроса, написанного с помощью JOIN и предложения WHERE, чтобы увидеть, какие различия выделяются.

Наконец, как говорили другие, с этими двумя следует обращаться одинаково любым подходящим оптимизатором, включая тот, который встроен в SQL Server.

0
ответ дан 24 November 2019 в 08:56
поделиться

Это быстрее? Попробуйте и убедитесь.

Что легче читать? Первый вариант мне кажется более "правильным", поскольку перемещенное условие не имеет ничего общего с объединением.

0
ответ дан 24 November 2019 в 08:56
поделиться

Я предполагаю, что первый, потому что он делает более конкретный фильтр для данных. Но вы должны увидеть план выполнения , как и при любой оптимизации, потому что он может сильно отличаться в зависимости от размера данных, оборудования сервера и т. Д.

0
ответ дан 24 November 2019 в 08:56
поделиться

С любым оптимизатором запросов работает ни копейки .... они идентичны.

3
ответ дан 24 November 2019 в 08:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: