Índice de rendimiento en ON versus WHERE

26

Tengo dos mesas

@T1 TABLE
(
    Id INT,
    Date DATETIME
)

@T2 TABLE
(
    Id INT,
    Date DATETIME
)

Estas tablas tienen un índice no agrupado en (Id, Fecha)

Y me uno a estas mesas

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
WHERE 
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

Esto también se puede escribir como

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
    AND
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

Mi pregunta es, ¿cuál de estas dos consultas ofrece el mejor rendimiento y por qué? ¿O son iguales?

Erik Bergstedt
fuente
1
¿Realmente tiene un @table variabled con un índice no agrupado que cubra todos los campos y sin índice agrupado? o es solo una simplificación?
Remus Rusanu
1
Es una simplificación extrema
Erik Bergstedt

Respuestas:

32

El rendimiento será el mismo. El optimizador lo reconocerá y creará el mismo plan.

Por otro lado, no diría que son iguales. La primera forma en la pregunta es mucho más legible y generalmente esperada.

Para un ejemplo usando algunas tablas que tengo a mano, puede ver que el plan de ejecución es exactamente el mismo sin importar cómo escriba la consulta.

Sin embargo, debe poder determinar los planes de consulta para sus propias tablas y conjunto de datos para poder ver qué sucede en su situación.

SELECT * FROM salestable , custtable 
WHERE salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable 
JOIN  custtable 
ON salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable JOIN custtable 
ON salestable.custaccount = custtable.accountnum 
WHERE salestable.dataareaid = custtable.dataareaid

Da estos planes de ejecución

ingrese la descripción de la imagen aquí

Tom V - Equipo Mónica
fuente
Estoy de acuerdo, la primera forma es más fácil de leer y, por lo tanto, me alivia que sean iguales. Solo usaré este formulario en el futuro.
Erik Bergstedt
@ErikBergstedt Edité mi respuesta, deberías poder verificar esto para tu propio conjunto de datos y estructura de tabla con bastante facilidad cuando miras los planes de ejecución
Tom V - Team Monica
Sí, lo hice. Gracias. Solo estaba buscando una segunda opinión ya que no encontré ninguna respuesta existente.
Erik Bergstedt
Nota: SOLO son iguales si es un INNER JOIN. Si lanzas un lanzamiento, OUTER JOINentonces definitivamente no son lo mismo.
Kenneth Fisher
22

Son semánticamente idénticos y el optimizador no debería tener problemas para reconocer este hecho y generar planes idénticos.

Tiendo a poner condiciones que hacen referencia a ambas tablas en ONy condiciones que hacen referencia a una sola tabla en WHERE.

OUTER JOINSSin embargo, para moverse, las condiciones pueden afectar la semántica.

Martin Smith
fuente
7

En casos simples, será lo mismo. Sin embargo, he visto consultas muy complejas con varias combinaciones que tienen planes significativamente diferentes. Una reciente en la que estaba trabajando comenzó con una tabla que tiene cerca de 6 millones de filas unidas a unas 20 tablas diferentes. Solo la primera unión a esta tabla fue una unión interna , todas las demás quedaron juntas externas. El filtro en la cláusula where se parametrizó de la siguiente manera:

WHERE table1.begindate >= @startdate AND table1.enddate < @enddate 

Este filtro se usó más tarde en el plan en lugar de antes. Cuando moví estas condiciones a la primera unión interna, el plan cambió drásticamente a medida que el filtro se aplicó al principio del plan para limitar el conjunto de resultados y mi CPU y el tiempo transcurrido disminuyeron aproximadamente un 310%. Entonces, como con muchas preguntas de SQL Server, depende.

Jared Karney
fuente
2
¿Podría agregar más detalles, tal vez capturas de pantalla de los diagramas del plan de ejecución, ya que su respuesta parece contradecir a todos los demás?
Kenny Evitt
2
¿El plan mostró un tiempo de espera optimizador?
Martin Smith
¿Cómo puede caer la carga de la CPU en más del 100%?
Michael Green
2

En general, donde pones los filtros hace la diferencia.
Si bien Tom V dice que el Optimizador reconocerá que las consultas son las mismas y propondrá el mismo plan, eso no siempre es cierto. Depende de la versión de SQL en la que se encuentre, la complejidad de su consulta y la importancia del lote general que el Optimizer determina que es la consulta.

El Optimizador puede decidir que esta parte del lote no vale la pena dedicar el tiempo suficiente para permitirle encontrar el mejor plan. En general, obtendrá un mejor rendimiento si coloca condiciones que reducen la cantidad de datos en los que la consulta necesitará trabajar en la cláusula ON en lugar de la cláusula WHERE (si es posible, ya que hacer esto con una combinación externa dará como resultado un producto cartesiano .)

Es un poco más fácil para el desarrollador SQL ocasional detectar filtros en la cláusula WHERE, pero he trabajado en algunas tablas grandes donde tener los filtros en la cláusula ON recorta horas del tiempo de ejecución.

Entonces, si la cláusula tiene el potencial de reducir drásticamente el número de filas que leerá la consulta, siempre la pondré en la cláusula ON para ayudar al Optimizador a elegir el mejor plan.

Tom Evers
fuente
1

En circunstancias normales, las condiciones de filtro se pueden especificar en las cláusulas WHERE o JOIN. Tiendo a colocar filtros debajo de DONDE, a menos que la prioridad de OUTER JOIN pueda verse afectada (ver más abajo) o si el filtro es muy específico para esa tabla (por ejemplo, TYPE = 12 para especificar un subconjunto específico de filas en la tabla).

Por otro lado, las cláusulas ON y WHERE pueden usarse para especificar condiciones de unión (en oposición a las condiciones de filtro). Mientras use solo combinaciones INNER, no importará cuál use en circunstancias normales.

Sin embargo, si está utilizando combinaciones OUTER, puede hacer una gran diferencia. Si, por ejemplo, especifica una UNIÓN EXTERNA entre dos tablas (t1 y t2) pero luego, en la cláusula WHERE, especifica una relación eqijoin entre las tablas (por ejemplo, t1.col = t2.col), simplemente tiene ¡Convirtió la unión EXTERIOR en una unión INTERNA! Esto se debe a que WHERE se puede usar para especificar un equijoin (o tal vez incluso una unión OUTER, dependiendo de la versión, usando la sintaxis obsoleta * =) sin usar una cláusula ON, y cuando WHERE indica un equijoin interno entre las tablas, anula un OUTER ÚNETE (si está presente).

La pregunta original era acerca de los filtros, donde el tipo de unión a menudo no debería ser un problema, pero una unión también puede actuar como un filtro y en esas situaciones la ubicación de la condición de unión ciertamente puede importar.

McB2K3
fuente
-1

Con INNER JOINs, es un problema de estilo.

Sin embargo, se vuelve mucho más interesante con OUTER JOINs. Debe explorar las diferencias entre las consultas con OUTER JOIN y las condiciones tanto en la cláusula ON como en la cláusula WHERE. El conjunto de resultados no siempre es el mismo. Es, por ejemplo,

OUTER JOIN dbo.x ON a.ID = x.ID ... WHERE x.SomeField IS NOT NULL

lo mismo que

INNER JOIN dbo.x ON a.ID = x.ID AND x.SomeField IS NOT NULL
Sean Redmond
fuente
8
Si el resultado es diferente (que es, por supuesto), ¿cuál es el punto de comparar el rendimiento?
ypercubeᵀᴹ