Какой 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
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 предназначен для объединения таблиц
- где находится для фильтрации результатов
хотя вы можете использовать их по-разному, мне всегда кажется, что это запах.
сделки с производительностью, когда это проблема. Тогда вы можете посмотреть на такие "оптимизации".
маловероятно, что размещение этого соединения будет решающим фактором для производительности. Я не очень хорошо знаком с планированием выполнения для tsql, но вполне вероятно, что они будут автоматически оптимизированы для аналогичных планов.
правило #0: запустите некоторые тесты и посмотрите! Единственный способ действительно сказать, что будет быстрее, - это попробовать. Эти типы тестов очень легко выполнить с помощью SQL profiler.
кроме того, изучите план выполнения для запроса, написанного с помощью JOIN и с предложением WHERE, чтобы увидеть, какие различия выделяются.
наконец, как говорили другие, эти два должны рассматриваться одинаково любым приличным оптимизатором, включая встроенный в SQL Server.
это быстрее? Попробуй и увидишь.
Что легче читать? Первый для меня выглядит более "правильным", так как перемещенное условие не имеет ничего общего с соединением.
Я думаю, что первый, потому что он делает более конкретный фильтр по данным. Но ты должен увидеть план выполнения, как и при любой оптимизации, потому что она может быть очень разной в зависимости от размера данных, серверного оборудования и т. д.
Comments