다른 답변은 구문 차이를 잘 다루므로 이에 들어 가지 않습니다. 대신이 답변은 Oracle의 성능 만 다룹니다.
Oracle Optimizer는 CTE 결과를 내부 임시 테이블로 구체화하도록 선택할 수 있습니다. 비용 기반 최적화 대신 휴리스틱을 사용하여이를 수행합니다. 휴리스틱은 "사소한 표현이 아니고 CTE가 쿼리에서 두 번 이상 참조되는 경우 CTE를 자료 화"와 같은 것입니다. 구체화가 성능을 향상시키는 몇 가지 쿼리가 있습니다. 구체화가 성능을 크게 저하시키는 몇 가지 쿼리가 있습니다. 다음 예제는 약간 고안되었지만 요점을 잘 보여줍니다.
먼저 1에서 10000 사이의 정수를 포함하는 기본 키가있는 테이블을 작성하십시오.
CREATE TABLE N_10000 (NUM_ID INTEGER NOT NULL, PRIMARY KEY (NUM_ID));
INSERT /*+APPEND */ INTO N_10000
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= 10000
ORDER BY LEVEL;
COMMIT;
두 개의 파생 테이블을 사용하는 다음 쿼리를 고려하십시오.
SELECT t1.NUM_ID
FROM
(
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
) t1
LEFT OUTER JOIN
(
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
) t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
이 쿼리를보고 어떤 행도 반환하지 않는지 빠르게 확인할 수 있습니다. 오라클은 인덱스를 사용하여이를 확인할 수 있어야합니다. 내 컴퓨터에서 쿼리는 다음 계획으로 거의 즉시 완료됩니다.
반복하는 것을 좋아하지 않으므로 CTE로 동일한 쿼리를 시도해 보겠습니다.
WITH N_10000_CTE AS (
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
)
SELECT t1.NUM_ID
FROM N_10000_CTE t1
LEFT JOIN N_10000_CTE t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
계획은 다음과 같습니다.
정말 나쁜 계획입니다. Oracle은 인덱스를 사용하는 대신 10000 X 10000 = 100000000 개의 행을 임시 테이블로 구체화하여 결국 0 개의 행을 반환합니다. 이 계획의 비용은 약 6M이며 다른 쿼리보다 훨씬 높습니다. 컴퓨터에서 쿼리를 마치는 데 68 초가 걸렸습니다.
임시 테이블 스페이스에 메모리 나 여유 공간이 충분하지 않으면 쿼리가 실패했을 수 있습니다.
문서화되지 않은 INLINE
힌트를 사용하여 옵티마이 저가 CTE를 구체화하지 못하게 할 수 있습니다 .
WITH N_10000_CTE AS (
SELECT /*+ INLINE */ n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
)
SELECT t1.NUM_ID
FROM N_10000_CTE t1
LEFT JOIN N_10000_CTE t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
이 쿼리는 인덱스를 사용할 수 있으며 거의 즉시 완료됩니다. 쿼리 비용은 이전 11과 같습니다. 따라서 두 번째 쿼리의 경우 Oracle에서 사용하는 휴리스틱을 통해 예상 비용이 11 인 쿼리 대신 6M의 예상 비용으로 쿼리를 선택했습니다.
WITH...
)입니다. 모든 파생 테이블을 CTE로 다시 작성할 수 있지만 다른 방법으로는 불가능합니다 (예 : 재귀 CTE 또는 CTE를 여러 번 사용)