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



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



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



запрос 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


EDIT



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



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



ПРОШЛО ВРЕМЯ, КОГДА КРИТЕРИИ: 143016 МС
ПРОШЕДШЕЕ ВРЕМЯ КРИТЕРИИ СОЕДИНЕНИЯ: 143256 ms



тест



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
665   8  

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) логически более последователен.

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

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

насколько эти два метода идут.

  • JOIN/ON предназначен для объединения таблиц
  • где находится для фильтрации результатов

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

сделки с производительностью, когда это проблема. Тогда вы можете посмотреть на такие "оптимизации".

с любым оптимизатором запросов worh цент.... они идентичны.

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

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

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

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

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

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

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

Comments

    Ничего не найдено.