¿Existe alguna práctica recomendada entre el uso de un formato LEFT JOIN o NOT EXISTS?
¿Cuál es el beneficio de usar uno sobre el otro?
Si no hay ninguno, ¿cuál debería preferirse?
SELECT *
FROM tableA A
LEFT JOIN tableB B
ON A.idx = B.idx
WHERE B.idx IS NULL
SELECT *
FROM tableA A
WHERE NOT EXISTS
(SELECT idx FROM tableB B WHERE B.idx = A.idx)
Estoy usando consultas dentro de Access contra una base de datos de SQL Server.
sql-server
join
exists
Michael Richardson
fuente
fuente
WHERE A.idx NOT IN (...)
es no idéntica , debido al comportamiento de trivalenteNULL
(es decir,NULL
no es igual aNULL
(ni desigual), por lo tanto, si usted tiene cualquieraNULL
detableB
obtendrá resultados inesperados!)Respuestas:
La mayor diferencia no está en la combinación vs no existe, es (como está escrito), el
SELECT *
.En el primer ejemplo, obtienes todas las columnas de ambos
A
yB
, mientras que en el segundo ejemplo, obtienes solo columnas deA
.En SQL Server, la segunda variante es ligeramente más rápida en un ejemplo artificial muy simple:
Crea dos tablas de muestra:
Inserte 10,000 filas en cada tabla:
Eliminar cada quinta fila de la segunda tabla:
Realice las dos
SELECT
variantes de declaración de prueba :Planes de ejecución:
La segunda variante no necesita realizar la operación de filtro ya que puede usar el operador izquierdo anti-semi-unión.
fuente
Lógicamente son idénticos, pero
NOT EXISTS
está más cerca del AntiSemiJoin que está solicitando, y generalmente se prefiere. También resalta mejor que no puede acceder a las columnas en B, porque solo se usa como un filtro (en lugar de tenerlas disponibles con valores NULL).Hace muchos años (SQL Server 6.0 ish),
LEFT JOIN
fue más rápido, pero ese no ha sido el caso durante mucho tiempo. En estos días,NOT EXISTS
es marginalmente más rápido.El mayor impacto en Access es que el
JOIN
método tiene que completar la unión antes de filtrarla, construyendo el conjunto unido en la memoria. UsarloNOT EXISTS
verifica la fila pero no asigna espacio para las columnas. Además, deja de buscar una vez que encuentra una fila. El rendimiento varía un poco más en Access, pero una regla general es queNOT EXISTS
tiende a ser un poco más rápido. Me inclinaría menos a decir que es "la mejor práctica", ya que hay más factores involucrados.fuente
Una excepción que he notado por
NOT EXISTS
ser superior (aunque marginalmente)LEFT JOIN ... WHERE IS NULL
es cuando utilizo servidores vinculados .Al examinar los planes de ejecución, parece que el
NOT EXISTS
operador se ejecuta en forma de bucle anidado. Por el cual se ejecuta por fila (lo que supongo que tiene sentido).Ejemplo de plan de ejecución que demuestra este comportamiento:
fuente
INSERT INTO #t (a,b,c) SELECT a,b,c FROM LinkedServer.database.dbo.table WHERE x=y
luego ejecutandoNOT EXISTS (...)
esa copia temporal de la base de datos.En general, el motor creará un plan de ejecución basado esencialmente en:
Para 4):
El plan "no existe" alienta un plan basado en la búsqueda en la tabla B. Esta es una buena opción cuando la tabla A es pequeña y la tabla B es grande (y existe un índice en B).
El plan "anti-unión" es una buena opción cuando la tabla A es muy grande o la tabla B es muy pequeña o no hay índice en B y devuelve un gran conjunto de resultados.
Sin embargo, es solo un "estímulo", como una entrada ponderada. Un fuerte (1), (2), (3) a menudo hace la elección de (4) discutible.
(Ignorando el efecto de su ejemplo que devuelve diferentes columnas debido al *, abordado por la respuesta @MaxVernon).
fuente