Tengo una consulta que se ejecuta en 800 milisegundos en SQL Server 2012 y tarda unos 170 segundos en SQL Server 2014 . Creo que he reducido esto a una estimación de cardinalidad pobre para el Row Count Spooloperador. He leído un poco sobre los operadores de spool (por ejemplo, aquí y aquí ), pero todavía tengo problemas para entender algunas cosas:
- ¿Por qué esta consulta necesita un Row Count Spooloperador? No creo que sea necesario para la corrección, entonces, ¿qué optimización específica está tratando de proporcionar?
- ¿Por qué SQL Server estima que la unión al Row Count Spooloperador elimina todas las filas?
- ¿Es esto un error en SQL Server 2014? Si es así, presentaré en Connect. Pero me gustaría una comprensión más profunda primero.
Nota: Puedo reescribir la consulta como LEFT JOINo agregar índices a las tablas para lograr un rendimiento aceptable tanto en SQL Server 2012 como en SQL Server 2014. Por lo tanto, esta pregunta trata más sobre cómo entender esta consulta específica y planificar en profundidad y menos sobre cómo formular la consulta de manera diferente.
La consulta lenta
Vea este Pastebin para un script de prueba completo. Aquí está la consulta de prueba específica que estoy viendo:
-- Prune any existing customers from the set of potential new customers
-- This query is much slower than expected in SQL Server 2014 
SELECT *
FROM #potentialNewCustomers -- 10K rows
WHERE cust_nbr NOT IN (
    SELECT cust_nbr
    FROM #existingCustomers -- 1MM rows
)
SQL Server 2014: el plan de consulta estimado
SQL Server considera que el Left Anti Semi Joinal Row Count Spoolfiltrará los 10.000 filas por debajo de 1 fila. Por este motivo, selecciona a LOOP JOINpara la unión posterior a #existingCustomers.
SQL Server 2014: el plan de consulta real
Como era de esperar (¡todos menos SQL Server!), Row Count SpoolNo eliminó ninguna fila. Por lo tanto, estamos realizando un ciclo de 10,000 veces cuando SQL Server esperaba que se repitiera solo una vez.
SQL Server 2012: el plan de consulta estimado
Cuando se usa SQL Server 2012 (o OPTION (QUERYTRACEON 9481)en SQL Server 2014), Row Count Spoolno reduce el número estimado de filas y se elige una combinación hash, lo que resulta en un plan mucho mejor.
La REUNIÓN DE LA IZQUIERDA
Como referencia, aquí hay una forma en la que puedo volver a escribir la consulta para lograr un buen rendimiento en todos los SQL Server 2012, 2014 y 2016. Sin embargo, todavía estoy interesado en el comportamiento específico de la consulta anterior y si es un error en el nuevo estimador de cardinalidad de SQL Server 2014.
-- Re-writing with LEFT JOIN yields much better performance in 2012/2014/2016
SELECT n.*
FROM #potentialNewCustomers n
LEFT JOIN (SELECT 1 AS test, cust_nbr FROM #existingCustomers) c
    ON c.cust_nbr = n.cust_nbr
WHERE c.test IS NULLfuente







