Compare estas 2 consultas. ¿Es más rápido poner el filtro en los criterios de combinación o en la WHERE
cláusula? Siempre he sentido que es más rápido en los criterios de combinación porque reduce el conjunto de resultados en el momento más rápido posible, pero no estoy seguro.
Voy a construir algunas pruebas para ver, pero también quería obtener opiniones sobre cuál sería más claro de leer.
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
Ejecuté algunas pruebas y los resultados muestran que en realidad está muy cerca, ¡pero la WHERE
cláusula es en realidad un poco más rápida! =)
Estoy absolutamente de acuerdo en que tiene más sentido aplicar el filtro a la WHERE
cláusula, solo tenía curiosidad por las implicaciones de rendimiento.
TIEMPO TRANSCURRIDO DONDE LOS CRITERIOS: 143016 ms
TIEMPO TRANSCURRIDO UNIR LOS CRITERIOS: 143256 ms
PRUEBA
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
fuente
Respuestas:
En cuanto al rendimiento, son iguales (y producen los mismos planes)
Lógicamente, debe realizar la operación que aún tiene sentido si reemplaza
INNER JOIN
con unLEFT JOIN
.En su caso, esto se verá así:
o esto:
La consulta anterior no devolverá coincidencias reales para
a.id
otro que1
, por lo que la última sintaxis (conWHERE
) es lógicamente más coherente.fuente
a.id = 1
aplica solo a la intersección, no a la parte izquierda que excluye la intersección.a.id != 1
, el otro solo tendrá filas dondea.id = 1
.Para las uniones internas, no importa dónde pongas tus criterios. El compilador SQL transformará ambos en un plan de ejecución en el que el filtrado ocurre debajo de la combinación (es decir, como si las expresiones de filtro aparecieran en la condición de combinación).
Las combinaciones externas son un asunto diferente, ya que el lugar del filtro cambia la semántica de la consulta.
fuente
En cuanto a los dos métodos.
Si bien puedes usarlos de manera diferente, siempre me parece un olor.
Ocúpese del rendimiento cuando sea un problema. Entonces puede examinar esas "optimizaciones".
fuente
Con cualquier optimizador de consultas digno de un centavo ... son idénticos.
fuente
En postgresql son iguales. Lo sabemos porque si lo haces
explain analyze
en cada una de las consultas, el plan resulta ser el mismo. Toma este ejemplo:Ambos tienen el mismo costo mínimo y máximo, así como el mismo plan de consulta. Además, observe que incluso en la consulta superior, team_score_2 se aplica como un 'Filtro'.
fuente
Es muy poco probable que la ubicación de esta unión sea el factor decisivo para el rendimiento. No estoy muy familiarizado con la planificación de la ejecución de tsql, pero es probable que se optimicen automáticamente para planes similares.
fuente
Regla n. ° 0: ¡Ejecute algunos puntos de referencia y vea! La única forma de saber realmente cuál será más rápido es probándolo. Estos tipos de pruebas comparativas son muy fáciles de realizar utilizando el generador de perfiles SQL.
Además, examine el plan de ejecución para la consulta escrita con una JOIN y con una cláusula WHERE para ver qué diferencias se destacan.
Finalmente, como han dicho otros, estos dos deben ser tratados de manera idéntica por cualquier optimizador decente, incluido el integrado en SQL Server.
fuente
Es mas rapido? Pruébalo y verás.
¿Cuál es más fácil de leer? El primero me parece más "correcto", ya que la condición de movimiento no tiene nada que ver con la unión.
fuente
Supongo que el primero, porque hace un filtro más específico sobre los datos. Pero debería ver el plan de ejecución , como con cualquier optimización, porque puede ser muy diferente según el tamaño de los datos, el hardware del servidor, etc.
fuente