공통 테이블 표현식
공통 테이블 표현식은 이름이 있는 서브쿼리를 의미합니다. 테이블 표현식이 허용되는SELECT 쿼리라면 어느 위치에서든 이름으로 참조할 수 있습니다.
이름이 있는 서브쿼리는 현재 쿼리의 범위 내에서, 또는 하위 서브쿼리의 범위 내에서 이름으로 참조할 수 있습니다.
SELECT 쿼리에서 공통 테이블 표현식에 대한 모든 참조는 CTE가 명시적으로 구체화된 것으로 정의되지 않은 한(Materialized Common Table Expressions 참조), 항상 해당 정의의 서브쿼리로 대체됩니다.
재귀는 현재 CTE를 식별자 해석 과정에서 숨겨 방지합니다.
CTE는 호출되는 모든 위치에서 동일한 결과를 보장하지 않는다는 점에 유의하십시오. 사용될 때마다 쿼리가 다시 실행되기 때문입니다.
구문
예시
서브쿼리가 다시 실행되는 경우의 예시는 다음과 같습니다:1000000이 표시됩니다.
하지만 cte_numbers를 두 번 참조하기 때문에 매번 난수가 생성되고, 그 결과 280501, 392454, 261636, 196227 등 서로 다른 값이 표시됩니다…
구체화된 공통 테이블 표현식
기본적으로 ClickHouse는 CTE의 서브쿼리를 참조되는 각 지점에 인라인하므로, 참조될 때마다 다시 실행합니다.MATERIALIZED 키워드를 추가하면 ClickHouse는 CTE 서브쿼리를 정확히 한 번만 실행하고, 그 결과를 임시 테이블에 저장한 다음, 모든 참조가 해당 테이블에서 결과를 가져오도록 합니다.
따라서 동일한 CTE가 하나의 쿼리에서 여러 번 참조되는 경우(예: 셀프 조인 또는 여러 IN 서브쿼리) 특히 유용합니다. 기본 계산은 한 번만 수행되기 때문입니다.
구체화된 CTE는 실험적 기능입니다.
사용하려면 설정
enable_materialized_cte가 활성화되어 있어야 합니다.
이 설정이 비활성화되어 있으면 MATERIALIZED 키워드는 무시됩니다. 즉, CTE는 일반 CTE처럼 각 참조 지점에 인라인되며 경고가 기록됩니다.구문
사용하면 좋은 경우
구체화된 CTE는 다음과 같은 경우에 특히 유용합니다.- 하나의 쿼리에서 동일한 CTE를 두 번 이상 참조하는 경우입니다.
MATERIALIZED를 사용하지 않으면 각 참조마다 서브쿼리가 독립적으로 다시 실행됩니다. - CTE에
generateRandom과 같은 비결정적 함수가 포함된 경우입니다. 구체화하면 모든 참조에서 동일한 데이터를 보게 됩니다. - CTE에 비용이 큰 계산(집계, 조인, 대규모 스캔)이 포함되어 있어 반복 실행을 피해야 하는 경우입니다.
예시
예시 1: 구체화된 CTE에 대한 셀프 조인MATERIALIZED가 없으면 조인의 양쪽에서 각각 서브쿼리를 독립적으로 실행합니다.
MATERIALIZED를 사용하면 테이블을 한 번만 스캔하고, 조인의 양쪽이 동일한 임시 테이블에서 읽습니다.
generateRandom을 사용하면 참조할 때마다 서로 다른 결과가 생성됩니다.
CTE를 구체화하면 일관성이 보장됩니다:
1000000입니다.
예시 3: 구체화된 CTE 연결하기
구체화된 CTE는 다른 구체화된 CTE를 참조할 수 있습니다.
ClickHouse는 종속성을 해결하고 올바른 순서로 구체화합니다.
제약 사항
- 실험적 설정 필요:
enable_materialized_cte설정을 활성화해야 합니다. 비활성화된 경우MATERIALIZED키워드는 무시됩니다. 즉, CTE는 일반 CTE처럼 각 참조 위치에 인라인되며, 경고가 로그에 기록됩니다. RECURSIVE와 함께 사용할 수 없음:MATERIALIZED와RECURSIVE키워드를 함께 사용하는 것은 허용되지 않으며,UNSUPPORTED_METHOD예외가 발생합니다.- 상관 CTE 사용 금지: 구체화된 CTE는 외부 쿼리 범위의 컬럼을 참조할 수 없습니다.
공통 스칼라 표현식
ClickHouse에서는WITH 절에서 임의의 스칼라 표현식에 대한 별칭을 선언할 수 있습니다.
공통 스칼라 표현식은 쿼리의 어느 위치에서나 참조할 수 있습니다.
구문
예시
예시 1: 상수 표현식을 “변수”처럼 사용하기extension은 gen_name 람다 함수 본문에서 바인딩되어 있지 않습니다.
extension은 generated_names의 정의 및 사용 범위에서 공통 스칼라 표현식으로 '.txt'로 정의되어 있지만, generated_names 서브쿼리(subquery)에서 사용할 수 있으므로 테이블 extension_list의 컬럼(column)으로 해석됩니다.
재귀 쿼리
선택적RECURSIVE 수정자를 사용하면 WITH 쿼리가 자신의 출력 결과를 참조할 수 있습니다. 예시:
예시: 1부터 100까지 정수의 합
재귀 CTE는 버전 **
24.3**에 도입된 쿼리 분석기에 의존하며, 해당 버전부터 기본으로 사용되고 **26.9**부터는 필수입니다. 인스턴스, role 또는 profile에서 분석기가 여전히 비활성화되어 있는 이전 버전에서는 재귀 CTE가 (UNKNOWN_TABLE) 또는 (UNSUPPORTED_METHOD) 예외를 발생시킵니다. 해당 환경에서 enable_analyzer 설정을 활성화하거나 업그레이드하십시오.WITH 쿼리의 일반적인 형태는 항상 비재귀 항, 그다음 UNION ALL, 그다음 재귀 항으로 이루어집니다. 이때 쿼리 자신의 출력에 대한 참조를 포함할 수 있는 것은 재귀 항뿐입니다. 재귀 CTE 쿼리는 다음과 같이 실행됩니다:
- 비재귀 항을 평가합니다. 비재귀 항 쿼리의 결과를 임시 작업 테이블에 저장합니다.
- 작업 테이블이 비어 있지 않은 동안 다음 단계를 반복합니다:
- 재귀 항을 평가하면서, 재귀 자기 참조를 작업 테이블의 현재 내용으로 치환합니다. 재귀 항 쿼리의 결과를 임시 중간 테이블에 저장합니다.
- 작업 테이블의 내용을 중간 테이블의 내용으로 대체한 다음, 중간 테이블을 비웁니다.
탐색 순서
깊이 우선 순서를 만들기 위해 각 결과 행마다 지금까지 방문한 행의 배열을 계산합니다: 예시: 트리 순회의 깊이 우선 순서사이클 감지
먼저 그래프 테이블을 만들어 보겠습니다:Maximum recursive CTE evaluation depth 오류로 실패합니다:
무한 쿼리
외부 쿼리에서LIMIT를 사용하면 무한 재귀 CTE 쿼리도 사용할 수 있습니다:
예시: 무한 재귀 CTE 쿼리
후행 쉼표
WITH 절의 마지막 요소 뒤에도 쉼표를 사용할 수 있습니다: