¿Cuál de estas consultas es la más rápida?
NO EXISTE:
SELECT ProductID, ProductName
FROM Northwind..Products p
WHERE NOT EXISTS (
SELECT 1
FROM Northwind..[Order Details] od
WHERE p.ProductId = od.ProductId)
O NO EN:
SELECT ProductID, ProductName
FROM Northwind..Products p
WHERE p.ProductID NOT IN (
SELECT ProductID
FROM Northwind..[Order Details])
El plan de ejecución de la consulta dice que ambos hacen lo mismo. Si ese es el caso, ¿cuál es la forma recomendada?
Esto se basa en la base de datos NorthWind.
[Editar]
Acabo de encontrar este útil artículo: http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx
Creo que me quedaré con NO EXISTE.
sql
sql-server
notin
ilitirit
fuente
fuente
NOT IN
consulta:SELECT "A".* FROM "A" WHERE "A"."id" NOT IN (SELECT "B"."Aid" FROM "B" WHERE "B"."Uid" = 2)
es casi 30 veces más rápida que estaNOT EXISTS
:SELECT "A".* FROM "A" WHERE (NOT (EXISTS (SELECT 1 FROM "B" WHERE "B"."user_id" = 2 AND "B"."Aid" = "A"."id")))
Respuestas:
Siempre por defecto
NOT EXISTS
.Los planes de ejecución pueden ser los mismos en este momento, pero si alguna de las columnas se modifica en el futuro para permitir que
NULL
laNOT IN
versión tenga que hacer más trabajo (incluso si no hayNULL
s realmente presentes en los datos) y la semántica deNOT IN
ifNULL
s está presente es poco probable que sean los que quieres de todos modos.Cuando ninguno
Products.ProductID
o[Order Details].ProductID
permitir queNULL
s elNOT IN
serán tratados de forma idéntica a la siguiente consulta.El plan exacto puede variar, pero para mis datos de ejemplo obtengo lo siguiente.
Una idea errónea razonablemente común parece ser que las subconsultas correlacionadas siempre son "malas" en comparación con las uniones. Ciertamente pueden ser cuando fuerzan un plan de bucles anidados (subconsulta evaluada fila por fila) pero este plan incluye un operador lógico anti semiunión. Las semiuniones anti no están restringidas a bucles anidados, sino que también pueden usar combinaciones hash o merge (como en este ejemplo).
Si
[Order Details].ProductID
esNULL
posible, la consulta se convierte enLa razón de esto es que la semántica correcta si
[Order Details]
contiene algunaNULL
ProductId
s es no devolver resultados. Vea el carrete extra anti semi join y row count para verificar esto que se agrega al plan.Si
Products.ProductID
también se cambia para que seNULL
pueda habilitar, la consulta se convierte enLa razón de esto es porque
NULL
Products.ProductId
no se debe devolver a en los resultados, excepto si laNOT IN
subconsulta no devuelve ningún resultado (es decir, la[Order Details]
tabla está vacía). En cuyo caso debería. En el plan para mis datos de muestra, esto se implementa mediante la adición de otra semi-unión como se muestra a continuación.El efecto de esto se muestra en la publicación del blog ya vinculada por Buckley . En el ejemplo allí, el número de lecturas lógicas aumenta de alrededor de 400 a 500,000.
Además, el hecho de que un solo
NULL
puede reducir el recuento de filas a cero hace que la estimación de la cardinalidad sea muy difícil. Si SQL Server asume que esto sucederá, pero de hecho no habíaNULL
filas en los datos, el resto del plan de ejecución puede ser catastróficamente peor, si esto es solo parte de una consulta más grande, con bucles anidados inapropiados que causan la ejecución repetida de un sub costoso árbol por ejemplo .Sin embargo, este no es el único plan de ejecución posible para una columna
NOT IN
en unaNULL
tabla. Este artículo muestra otro para una consulta en laAdventureWorks2008
base de datos.Para el
NOT IN
en unaNOT NULL
columna o enNOT EXISTS
contra de una columna anulable o no anulable da el siguiente plan.Cuando la columna cambia a
NULL
-able, elNOT IN
plan ahora se ve comoAgrega un operador de unión interno adicional al plan. Este aparato se explica aquí . Está todo allí para convertir la búsqueda de índice correlacionada anterior simple en
Sales.SalesOrderDetail.ProductID = <correlated_product_id>
dos búsquedas por fila exterior. El adicional está encendidoWHERE Sales.SalesOrderDetail.ProductID IS NULL
.Como esto está bajo una semi-unión si esa devuelve alguna fila, la segunda búsqueda no ocurrirá. Sin embargo, si
Sales.SalesOrderDetail
no contiene ningunoNULL
ProductID
, duplicará el número de operaciones de búsqueda requeridas.fuente
NOT EXISTS
funciona de la manera que esperoNOT IN
que funcione (lo cual, no es así).También tenga en cuenta que NOT IN no es equivalente a NOT EXISTS cuando se trata de nulo.
Este post lo explica muy bien
http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/
fuente
Si el planificador de ejecución dice que son lo mismo, son lo mismo. Use el que haga que su intención sea más obvia, en este caso, la segunda.
fuente
En realidad, creo que este sería el más rápido:
fuente
Tengo una tabla que tiene aproximadamente 120,000 registros y necesito seleccionar solo aquellos que no existen (emparejados con una columna varchar) en otras cuatro tablas con un número de filas de aproximadamente 1500, 4000, 40000, 200. Todas las tablas involucradas tienen un índice único en la
Varchar
columna correspondiente .NOT IN
tomó unos 10 minutos,NOT EXISTS
tomó 4 segundos.Tengo una consulta recursiva que podría tener una sección no ajustada que podría haber contribuido a los 10 minutos, pero la otra opción que toma 4 segundos explica, al menos para mí eso
NOT EXISTS
es mucho mejor o al menos esoIN
yEXISTS
no son exactamente lo mismo y siempre valen la pena. verifique antes de continuar con el código.fuente
En su ejemplo específico, son iguales, porque el optimizador ha descubierto que lo que está tratando de hacer es lo mismo en ambos ejemplos. Pero es posible que en ejemplos no triviales el optimizador no haga esto, y en ese caso hay razones para preferir uno a otro en ocasiones.
NOT IN
debe preferirse si está probando varias filas en su selección externa. La subconsulta dentro de laNOT IN
declaración se puede evaluar al comienzo de la ejecución, y la tabla temporal se puede verificar contra cada valor en la selección externa, en lugar de volver a ejecutar la subselección cada vez que se requeriría con laNOT EXISTS
declaración.Si la subconsulta debe correlacionarse con la selección externa, entonces
NOT EXISTS
puede ser preferible, ya que el optimizador puede descubrir una simplificación que impide la creación de tablas temporales para realizar la misma función.fuente
Yo estaba usando
y descubrí que estaba dando resultados incorrectos (por incorrecto quiero decir que no hay resultados). Como había un NULL en TABLE2.Col1.
Al cambiar la consulta a
me dio los resultados correctos.
Desde entonces, comencé a usar NO EXISTE en todas partes.
fuente
Son muy similares pero no son realmente lo mismo.
En términos de eficiencia, descubrí que la combinación izquierda es más nula (cuando se selecciona una gran cantidad de filas)
fuente
Si el optimizador dice que son iguales, considere el factor humano. Prefiero ver NO EXISTE :)
fuente
Modelo de tabla de base de datos
Supongamos que tenemos las siguientes dos tablas en nuestra base de datos, que forman una relación de tabla de uno a muchos.
La
student
tabla es el padre, y elstudent_grade
tabla secundaria, ya que tiene una columna de clave externa student_id que hace referencia a la columna de clave principal id en la tabla del alumno.El
student table
contiene los siguientes dos registros:Y, la
student_grade
tabla almacena las calificaciones que recibieron los estudiantes:SQL EXISTE
Digamos que queremos que todos los estudiantes que hayan recibido un grado 10 en la clase de matemáticas.
Si solo estamos interesados en el identificador de estudiante, entonces podemos ejecutar una consulta como esta:
Pero, la aplicación está interesada en mostrar el nombre completo de a
student
, no solo el identificador, por lo que también necesitamos información de lastudent
tabla.Para filtrar los
student
registros que tienen una calificación de 10 en matemáticas, podemos usar el operador EXISTS SQL, así:Al ejecutar la consulta anterior, podemos ver que solo se selecciona la fila Alice:
La consulta externa selecciona las
student
columnas de fila que estamos interesados en devolver al cliente. Sin embargo, la cláusula WHERE está utilizando el operador EXISTS con una subconsulta interna asociada.El operador EXISTS devuelve verdadero si la subconsulta devuelve al menos un registro y falso si no se selecciona ninguna fila. El motor de base de datos no tiene que ejecutar la subconsulta por completo. Si se coincide con un solo registro, el operador EXISTS devuelve verdadero y se selecciona la otra fila de consulta asociada.
La subconsulta interna está correlacionada porque la columna student_id de la
student_grade
tabla se compara con la columna id de la tabla externa del estudiante.SQL NO EXISTE
Consideremos que queremos seleccionar a todos los estudiantes que no tengan una calificación inferior a 9. Para esto, podemos usar NOT EXISTS, que niega la lógica del operador EXISTS.
Por lo tanto, el operador NO EXISTE devuelve verdadero si la subconsulta subyacente no devuelve ningún registro. Sin embargo, si la subconsulta interna coincide con un solo registro, el operador NO EXISTE devolverá falso y la ejecución de la subconsulta puede detenerse.
Para hacer coincidir todos los registros de estudiantes que no tienen un student_grade asociado con un valor inferior a 9, podemos ejecutar la siguiente consulta SQL:
Al ejecutar la consulta anterior, podemos ver que solo coincide el registro de Alice:
Por lo tanto, la ventaja de utilizar los operadores SQL EXISTS y NOT EXISTS es que la ejecución de la subconsulta interna se puede detener siempre que se encuentre un registro coincidente.
fuente
Depende..
no sería relativamente lento, no hay mucho para limitar el tamaño de lo que la consulta verifica si la clave está activada. EXISTA sería preferible en este caso.
Pero, dependiendo del optimizador del DBMS, esto no podría ser diferente.
Como un ejemplo de cuándo EXISTE es mejor
fuente
IN
yEXISTS
obtener el mismo plan en SQL Server . La pregunta es sobreNOT IN
vs deNOT EXISTS
todos modos.