SQL es un lenguaje declarativo, no un lenguaje de procedimiento. Es decir, construye una declaración SQL para describir los resultados que desea. No le está diciendo al motor SQL cómo hacer el trabajo.
Como regla general, es una buena idea dejar que el motor SQL y el optimizador SQL encuentren el mejor plan de consulta. Hay muchos años-persona de esfuerzo para desarrollar un motor SQL, así que deje que los ingenieros hagan lo que saben hacer.
Por supuesto, hay situaciones en las que el plan de consulta no es óptimo. Luego, desea usar sugerencias de consulta, reestructurar la consulta, actualizar estadísticas, usar tablas temporales, agregar índices, etc. para obtener un mejor rendimiento.
En cuanto a tu pregunta. El rendimiento de los CTE y las subconsultas debería, en teoría, ser el mismo, ya que ambos proporcionan la misma información al optimizador de consultas. Una diferencia es que un CTE usado más de una vez podría identificarse y calcularse fácilmente una vez. Los resultados podrían almacenarse y leerse varias veces. Desafortunadamente, SQL Server no parece aprovechar este método básico de optimización (podría llamarse a esto eliminación de subconsulta común).
Las tablas temporales son una cuestión diferente, ya que proporciona más orientación sobre cómo se debe ejecutar la consulta. Una diferencia importante es que el optimizador puede usar estadísticas de la tabla temporal para establecer su plan de consulta. Esto puede resultar en ganancias de rendimiento. Además, si tiene un CTE (subconsulta) complicado que se usa más de una vez, almacenarlo en una tabla temporal a menudo le dará un impulso al rendimiento. La consulta se ejecuta solo una vez.
La respuesta a su pregunta es que necesita jugar para obtener el rendimiento que espera, particularmente para consultas complejas que se ejecutan regularmente. En un mundo ideal, el optimizador de consultas encontraría la ruta de ejecución perfecta. Aunque a menudo lo hace, es posible que pueda encontrar una manera de obtener un mejor rendimiento.