8

He escrito una UDF con valores de tabla que comienza por un CTE para devolver un subconjunto de las filas de una tabla grande. Hay varias combinaciones en la CTE. Un par de combinaciones internas y una izquierda se unen a otras tablas, que no contienen muchas filas. El CTE tiene una cláusula where que devuelve las filas dentro de un intervalo de fechas, con el fin de devolver sólo las filas necesarias.SQL Server CTE hace referencia en el mismo se une lenta

Estoy haciendo referencia a este CTE en 4 uniones a la izquierda, para construir subtotales con diferentes criterios.

La consulta es bastante complejo, pero aquí es un pseudo-versión simplificada de la misma

WITH DataCTE as 
(
    SELECT [columns] FROM table 
         INNER JOIN table2 
         ON [...] 

         INNER JOIN table3 
         ON [...] 

         LEFT JOIN table3 
         ON [...] 
) 
SELECT [aggregates_columns of each subset] FROM DataCTE Main 
LEFT JOIN DataCTE BananasSubset 
       ON [...] 
      AND Product = 'Bananas' 
      AND Quality = 100 
LEFT JOIN DataCTE DamagedBananasSubset 
       ON [...] 
      AND Product = 'Bananas' 
      AND Quality < 20 
LEFT JOIN DataCTE MangosSubset 
       ON [...] 
GROUP BY [ 

tengo la sensación de que SQL Server se confunde y llama a la CTE para cada auto unirse, que parece confirmada por mirar el plan de ejecución, aunque confieso que no soy un experto en leer esos.

Supongo que SQL Server es lo suficientemente inteligente como para realizar solo la recuperación de datos desde el CTE solo una vez, en lugar de hacerlo varias veces.

He intentado el mismo enfoque pero en lugar de usar un CTE para obtener el subconjunto de los datos, utilicé la misma consulta de selección que en el CTE, pero hice que fuera una tabla temporal en su lugar.

La versión en referencia la versión CTE tarda 40 segundos. La versión que hace referencia a la tabla temporal toma entre 1 y 2 segundos.

¿Por qué no es SQL Server lo suficientemente inteligente como para mantener los resultados de CTE en la memoria?

Me gustan los CTE, especialmente en este caso ya que mi UDF es una tabla de valor, por lo que me permitió mantener todo en una sola declaración.

Para usar una tabla temporal, necesitaría escribir una UDF con una tabla multi-declaración, que me parece una solución un poco menos elegante.

¿Alguno de ustedes tuvo este tipo de problemas de rendimiento con CTE y, de ser así, cómo los ordenó?

Gracias,

Kharlos

+0

¿Puede publicar su plan de ejecución? –

Respuesta

6

que creen que los resultados de CTE se recuperan cada vez. Con una tabla temporal, los resultados se almacenan hasta que se descarta. Esto parece explicar las mejoras en el rendimiento que vio cuando cambió a una tabla temporal.

Otra ventaja es que puede crear índices en una tabla temporal que no puede hacer a un cte. No estoy seguro de si habría un beneficio en su situación, pero es bueno saberlo.

Lectura relacionada:

Cita del último eslabón:

consulta subyacente del CTE será llamado cada vez que se hace referencia en la consulta inmediatamente siguiente.

Yo diría que vaya con la tabla de temperatura. Desafortunadamente elegante no siempre es la mejor solución.

ACTUALIZACIÓN:

Hmmm que hace las cosas más difíciles. Es difícil para mí decir sin mirar todo tu entorno.

Algunos pensamientos:

  • se puede utilizar un procedimiento almacenado en lugar de una UDF (en lugar, no desde dentro)?
  • Esto puede no ser posible, pero si puede eliminar el left join de su CTE, puede moverlo a una vista indizada. Si puede hacer esto, puede ver mejoras en el rendimiento incluso en la tabla temporal.
+0

Muchas gracias por estas excelentes referencias. Eso es lo que asumí entonces ... Tendré que abandonar la elegancia como dices, tener esta UDF con 40 segundos no es una opción. Espero que se optimice en una próxima versión de SQL Server ... Hasta entonces, probablemente tenderé a evitar los CTE ... Al menos, con una tabla temporal, puedo sentir más en control de lo que sucede detrás de escena. Gracias de nuevo. –

+0

Argh ... Había olvidado que incluso la UDF de varias instancias no puede usar tablas temporales. He intentado usar las variables de tabla en su lugar, pero el rendimiento es absolutamente terrible ... incluso peor que la de la versión CTE ... Mi subconjunto de datos es de unos 10 000 filas, pero puede ir hasta 100 000 en función de los parámetros suministrados por el usuario. ¿Cuáles son mis otras opciones teniendo en cuenta que * tiene * para volver mis datos como tabla a la persona que llama. Gracias. –

+0

Ver mi actualización. Lamentablemente, tengo la sensación de que ninguno de estos te va a funcionar. –

Cuestiones relacionadas