I think the general advice of this community is to avoid temp tables in favor of CTEs. However, I sometimes encounter situations in which CTE constructions are very slow, while their temp table equivalents are very fast.
For example, this spins for hours and never seems to yield results. The query plan is full of nested loops.
CREATE TABLE #TRIANGLES( NODE_A VARCHAR(22), NODE_B VARCHAR(22), NODE_C VARCHAR(22));INSERT INTO #TRIANGLES VALUES/* 150,000 ROWS */;CREATE NONCLUSTERED INDEX IDX_A ON #TRIANGLES (NODE_A);CREATE NONCLUSTERED INDEX IDX_B ON #TRIANGLES (NODE_B);CREATE NONCLUSTERED INDEX IDX_C ON #TRIANGLES (NODE_C);WITHTRIANGLES_FILTERED AS( -- **** FILTERING OF THE TRIANGLE TABLE OCCURS IN A CTE **** SELECT * FROM #TRIANGLES AS T WHERE LEN(T.NODE_A) = 2 AND LEN(T.NODE_B) = 2 AND LEN(T.NODE_C) = 2),CONNECTABLE_NODES AS( SELECT DISTINCT T1.NODE_C AS [NODE] FROM TRIANGLES_FILTERED AS T1 INNER JOIN TRIANGLES_FILTERED AS T2 ON T1.NODE_B = T2.NODE_A AND T1.NODE_C = T2.NODE_B INNER JOIN TRIANGLES_FILTERED AS T3 ON T2.NODE_B = T3.NODE_A AND T2.NODE_C = T3.NODE_B WHERE T1.NODE_A <> T2.NODE_C AND T1.NODE_A <> T3.NODE_C AND T2.NODE_A <> T3.NODE_C)SELECT *FROM #TRIANGLES AS T1WHERE T1.NODE_A IN (SELECT * FROM CONNECTABLE_NODES) AND T1.NODE_B IN (SELECT * FROM CONNECTABLE_NODES) AND T1.NODE_C IN (SELECT * FROM CONNECTABLE_NODES);
Query plan:https://www.brentozar.com/pastetheplan/?id=rk_5TaiiP
Whereas, the query plan for this uses hash matches and it runs in a flash:
CREATE TABLE #TRIANGLES( NODE_A VARCHAR(22), NODE_B VARCHAR(22), NODE_C VARCHAR(22));INSERT INTO #TRIANGLES VALUES/* 150,000 ROWS */;CREATE NONCLUSTERED INDEX IDX_A ON #TRIANGLES (NODE_A);CREATE NONCLUSTERED INDEX IDX_B ON #TRIANGLES (NODE_B);CREATE NONCLUSTERED INDEX IDX_C ON #TRIANGLES (NODE_C);-- **** FILTERING OF THE TRIANGLE TABLE SAVED INTO A TEMP TABLE ****SELECT *INTO #TRIANGLES_FILTEREDFROM #TRIANGLES AS TWHERE LEN(T.NODE_A) = 2 AND LEN(T.NODE_B) = 2 AND LEN(T.NODE_C) = 2; CREATE NONCLUSTERED INDEX IDX_A ON #TRIANGLES_FILTERED (NODE_A);CREATE NONCLUSTERED INDEX IDX_B ON #TRIANGLES_FILTERED (NODE_B);CREATE NONCLUSTERED INDEX IDX_C ON #TRIANGLES_FILTERED (NODE_C);WITHCONNECTABLE_NODES AS( SELECT DISTINCT T1.NODE_C AS [NODE] FROM #TRIANGLES_FILTERED AS T1 INNER JOIN #TRIANGLES_FILTERED AS T2 ON T1.NODE_B = T2.NODE_A AND T1.NODE_C = T2.NODE_B INNER JOIN #TRIANGLES_FILTERED AS T3 ON T2.NODE_B = T3.NODE_A AND T2.NODE_C = T3.NODE_B WHERE T1.NODE_A <> T2.NODE_C AND T1.NODE_A <> T3.NODE_C AND T2.NODE_A <> T3.NODE_C)SELECT *FROM #TRIANGLES AS T1WHERE T1.NODE_A IN (SELECT * FROM CONNECTABLE_NODES) AND T1.NODE_B IN (SELECT * FROM CONNECTABLE_NODES) AND T1.NODE_C IN (SELECT * FROM CONNECTABLE_NODES);
Query plan:https://www.brentozar.com/pastetheplan/?id=B1cZC6isD
How would I rewrite the first one to be as fast as a second one?
BTW, if you're wondering what all the geometry/topology is about, I needed to know how all the triangles connect with each other in the creation of this puzzle:
https://puzzling.stackexchange.com/questions/105275/dragon-summoning-spell