NO se debe evitar EN


14

Entre algunos desarrolladores de SQL Server, es una creencia generalizada que NOT INes terriblemente lenta , y las consultas deben reescribirse para que devuelvan el mismo resultado pero no utilicen las palabras clave "malvadas". ( ejemplo )

¿Hay algo de cierto en eso?

¿Existe, por ejemplo, algún error conocido en SQL Server (¿qué versión?) Que hace que las consultas NOT INtengan un plan de ejecución peor que una consulta equivalente que use

  • un LEFT JOINcombinado con un NULLcheque o
  • (SELECT COUNT(*) ...) = 0en la WHEREclausula?

77
Sin embargo, ese artículo es altamente inexacto. "In" no "tiene que ejecutar la misma consulta una y otra vez para cada fila en TableOne". El cartel allí parece creer que IN/ NOT INsiempre se implementará con bucles anidados. Y no tengo idea de lo que stops SQL Server from creating a ‘plan’se supone que significa.
Martin Smith

55
@Heinzi Ese artículo al que se vincula, debe morir en el fuego, está lleno de tonterías. Como: "Para reemplazar IN, usamos una UNIÓN INTERNA. Son efectivamente la misma cosa". El problema es que no son lo mismo. No confiaría en alguien que no conozca SQL básico, es decir, la diferencia entre una unión y una semiunión, para analizar cualquier cosa sobre el comportamiento del servidor SQL.
ypercubeᵀᴹ

Respuestas:


14

No creo que tenga nada que ver con ser terriblemente lento; tiene que ver con ser potencialmente inexacto. Por ejemplo, dados los siguientes datos: pedidos que pueden ser realizados por un cliente individual o un socio B2B:

DECLARE @Customers TABLE(CustomerID INT);

INSERT @Customers VALUES(1),(2);

DECLARE @Orders TABLE(OrderID INT, CustomerID INT, CompanyID INT);

INSERT @Orders VALUES(10,1,NULL),(11,NULL,5);

Digamos que quiero encontrar a todos los clientes que nunca han realizado un pedido. Dados los datos, solo hay uno: cliente # 2. Aquí hay tres formas en que podría escribir una consulta para encontrar esa información (hay otras):

SELECT [NOT IN] = CustomerID FROM @Customers 
  WHERE CustomerID NOT IN (SELECT CustomerID FROM @Orders);

SELECT [NOT EXISTS] = CustomerID FROM @Customers AS c 
  WHERE NOT EXISTS (SELECT 1 FROM @Orders AS o
  WHERE o.CustomerID = c.CustomerID);

SELECT [EXCEPT] = CustomerID FROM @Customers
EXCEPT SELECT CustomerID FROM @Orders;

Resultados:

NOT IN
------
                 -- <-- no results. Is that what you expected?

NOT EXISTS
----------
2

EXCEPT
------
2

Ahora, también hay algunos problemas de rendimiento, y hablo de ellos en esta publicación de blog . Dependiendo de los datos e índices, NOT EXISTSgeneralmente tendrá un rendimiento superior NOT IN, y no sé si alguna vez podría funcionar peor. También debe tener en cuenta que EXCEPTpuede introducir una operación de clasificación distinta, por lo que puede terminar con datos diferentes (nuevamente, dependiendo de la fuente). Y que el LEFT OUTER JOIN ... WHERE right.column IS NULLpatrón popular es siempre el de peor desempeño.

Martin Smith también tiene mucha buena información de respaldo en su respuesta sobre SO .

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.