Compare essas 2 consultas. É mais rápido colocar o filtro nos critérios de junção ou na WHERE
cláusula. Sempre achei que é mais rápido nos critérios de junção porque reduz o conjunto de resultados o mais rápido possível, mas não sei ao certo.
Vou construir alguns testes para ver, mas também gostaria de obter opiniões sobre quais seriam mais claras de ler também.
Consulta 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? */
Consulta 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
EDITAR
Fiz alguns testes e os resultados mostram que está muito próximo, mas a WHERE
cláusula é um pouco mais rápida! =)
Eu concordo totalmente que faz mais sentido aplicar o filtro na WHERE
cláusula, eu estava apenas curioso para saber as implicações de desempenho.
TEMPO REALIZADO ONDE CRITÉRIOS: 143016 ms
CRITÉRIOS DE REGISTRO DE TEMPO REALIZADO : 143256 ms
TESTE
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
sql
sql-server
tsql
sql-server-2008
Jon Erickson
fonte
fonte
Respostas:
Em termos de desempenho, eles são os mesmos (e produzem os mesmos planos)
Logicamente, você deve fazer a operação que ainda faz sentido se substituir
INNER JOIN
por aLEFT JOIN
.No seu caso, será assim:
ou isto:
A primeira consulta não retornará nenhuma correspondência real para
a.id
diferente de1
, portanto, a última sintaxe (comWHERE
) é logicamente mais consistente.fonte
a.id = 1
se aplica apenas à interseção, não à parte esquerda excluindo a interseção.a.id != 1
, o outro só terá linhas ondea.id = 1
.Para junções internas, não importa onde você coloca seus critérios. O compilador SQL transformará ambos em um plano de execução no qual a filtragem ocorre abaixo da junção (ou seja, como se as expressões de filtro aparecessem na condição de junção).
Junções externas são uma questão diferente, pois o lugar do filtro muda a semântica da consulta.
fonte
Até onde vão os dois métodos.
Embora você possa usá-los de maneira diferente, sempre parece um cheiro para mim.
Lide com o desempenho quando for um problema. Então, você pode examinar essas "otimizações".
fonte
Com qualquer otimizador de consulta que custa um centavo ... eles são idênticos.
fonte
No postgresql, eles são iguais. Sabemos disso porque se você fizer
explain analyze
em cada uma das consultas, o plano acaba sendo o mesmo. Veja este exemplo:Ambos têm o mesmo custo mínimo e máximo, bem como o mesmo plano de consulta. Além disso, observe que mesmo na consulta superior, team_score_2 é aplicado como um 'Filtro'.
fonte
É realmente improvável que o posicionamento dessa junção seja o fator decisivo para o desempenho. Não estou intimamente familiarizado com o planejamento de execução para tsql, mas é provável que eles sejam otimizados automaticamente para planos semelhantes.
fonte
Regra # 0: Execute alguns benchmarks e veja! A única maneira de realmente saber qual será o mais rápido é experimentando. Esses tipos de benchmarks são muito fáceis de executar usando o SQL Profiler.
Além disso, examine o plano de execução da consulta escrita com uma cláusula JOIN e WHERE para ver quais diferenças se destacam.
Finalmente, como outros já disseram, esses dois devem ser tratados de forma idêntica por qualquer otimizador decente, incluindo aquele embutido no SQL Server.
fonte
É mais rápido? Experimente e veja.
O que é mais fácil de ler? O primeiro para mim parece mais "correto", já que a condição movida não tem nada a ver com a junção.
fonte
Acho que é o primeiro, porque faz um filtro mais específico sobre os dados. Mas você deve ver o plano de execução , como acontece com qualquer otimização, porque pode ser muito diferente dependendo do tamanho dos dados, hardware do servidor, etc.
fonte