Acho que o conselho geral desta comunidade é evitar tabelas temporárias em favor de CTEs. No entanto, às vezes encontro situações em que as construções CTE são muito lentas, enquanto seus equivalentes de tabela temporária são muito rápidos.
Por exemplo, isso gira por horas e nunca parece produzir resultados. O plano de consulta está cheio de loops aninhados.
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);
WITH
TRIANGLES_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 T1
WHERE 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)
;
Plano de consulta: https://www.brentozar.com/pastetheplan/?id=rk_5TaiiP
Considerando que, o plano de consulta para isso usa correspondências de hash e é executado em um 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_FILTERED
FROM #TRIANGLES AS T
WHERE 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);
WITH
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 T1
WHERE 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)
;
Plano de consulta: https://www.brentozar.com/pastetheplan/?id=B1cZC6isD
Como eu reescreveria o primeiro para ser tão rápido quanto o segundo?
BTW, se você está se perguntando sobre o que é toda a geometria/topologia, eu precisava saber como todos os triângulos se conectam na criação deste quebra-cabeça:
https://puzzling.stackexchange.com/questions/105275/dragon -feitiço de invocação
Às vezes, o CTE tem uma estimativa errada. A tabela temporária é boa nisso.
Portanto, o CTE usa esses índices porque acha que há menos linhas. A razão para a lentidão do primeiro é RID Lookup. Se você descartar seus índices ou adicionar sua coluna de saída como include em seu index. Será mais rápido.
Tem um post incrível aqui no blog .
Acho que não há vitória entre eles. Você deve usá-los dependendo da situação. E tente os dois na mesma situação. Desta forma, você pode ver os custos.