EXPLAIN 타입
AST— 추상 구문 트리입니다.SYNTAX— AST 수준 최적화가 적용된 후의 쿼리 텍스트입니다.QUERY TREE— 쿼리 트리 수준 최적화가 적용된 후의 쿼리 트리입니다.PLAN— 쿼리 실행 계획입니다.PIPELINE— 쿼리 실행 파이프라인입니다.ANALYZE— 쿼리를 실행하고 측정된 런타임 메트릭을 실행 계획에 덧붙입니다.ESTIMATE— 쿼리 처리 중 테이블에서 읽을 것으로 예상되는 행 수, 마크 수 및 파트 수입니다.TABLE OVERRIDE— 테이블 함수 스키마에 적용된 테이블 재정의의 유효성이 검증된 결과입니다.
EXPLAIN AST
쿼리 AST를 출력합니다.SELECT뿐 아니라 모든 쿼리를 지원합니다.
설정:
graph– DOT 그래프 기술 언어로 표현된 그래프 형태로 AST를 출력합니다. 기본값: 0.
EXPLAIN 구문
구문 분석이 끝난 후 쿼리의 추상 구문 트리(AST)를 표시합니다. 쿼리를 파싱해 쿼리 AST와 쿼리 트리를 구성하고, 필요에 따라 쿼리 분석기와 최적화 패스를 실행한 뒤, 쿼리 트리를 다시 쿼리 AST로 변환하는 방식으로 수행됩니다. 설정:oneline– 쿼리를 한 줄로 출력합니다. 기본값:0.run_query_tree_passes– 쿼리 트리를 덤프하기 전에 쿼리 트리 패스를 실행합니다. 기본값:0.query_tree_passes–run_query_tree_passes가 설정된 경우 실행할 패스 수를 지정합니다.query_tree_passes를 지정하지 않으면 모든 패스를 실행합니다.single_record– 줄마다 하나의 레코드를 반환하는 대신, 재포맷된 쿼리를 여러 줄로 구성된 단일 레코드로 반환합니다. 기본값은1이며(explain_syntax_single_record설정으로 제어됨),0으로 설정하면 기존의 줄당 하나의 레코드 출력 형식으로 복원됩니다. 또는explain_syntax_single_record = 0을 설정하거나(전역 또는 쿼리별SETTINGS에서),compatibility를26.8보다 이전 버전으로 설정하십시오.
Query
Response
run_query_tree_passes를 사용하는 경우:
Query
Response
EXPLAIN QUERY TREE
설정:run_passes— 쿼리 트리를 덤프하기 전에 모든 쿼리 트리 패스를 실행합니다. 기본값:1.dump_passes— 쿼리 트리를 덤프하기 전에 사용된 패스 정보를 덤프합니다. 기본값:0.passes— 실행할 패스 수를 지정합니다.-1로 설정하면 모든 패스를 실행합니다. 기본값:-1.dump_tree— 쿼리 트리를 표시합니다. 기본값:1.dump_ast— 쿼리 트리에서 생성된 쿼리 AST를 표시합니다. 기본값:0.
EXPLAIN PLAN
쿼리 계획 단계를 덤프합니다. 설정:optimize— 계획을 표시하기 전에 쿼리 계획 최적화를 적용할지 제어합니다. 기본값: 1.header— 단계의 출력 헤더를 출력합니다. 기본값: 0.description— 단계 설명을 출력합니다. 기본값: 1.indexes— 사용된 인덱스와, 적용된 각 인덱스별로 필터링된 파트 수 및 필터링된 그래뉼 수를 표시합니다. 기본값: 0. MergeTree 테이블에서 지원됩니다. ClickHouse >= v25.9부터는 이 문을SETTINGS use_query_condition_cache = 0, use_skip_indexes_on_data_read = 0와 함께 사용할 때만 출력이 적절하게 표시됩니다.projections— 분석된 모든 프로젝션과, 프로젝션 프라이머리 키 조건에 기반한 파트 수준 필터링에 미치는 영향을 표시합니다. 각 프로젝션에 대해 이 섹션에는 프로젝션의 프라이머리 키를 사용해 평가된 파트 수, 행 수, 마크 수, 범위 수 등의 통계가 포함됩니다. 또한 프로젝션 자체를 읽지 않고도 이 필터링으로 인해 건너뛴 데이터 파트 수를 보여줍니다. 프로젝션이 실제 읽기에 사용되었는지, 아니면 필터링용으로만 분석되었는지는description필드로 확인할 수 있습니다. 기본값: 0. MergeTree 테이블에서 지원됩니다.actions— 단계 작업에 대한 자세한 정보를 출력합니다. 기본값: 1.sorting— 정렬된 출력을 생성하는 각 계획 단계의 정렬 설명을 출력합니다. 기본값: 0.keep_logical_steps— 조인을 물리적 조인 구현으로 변환하지 않고 논리적 계획 단계를 유지합니다. 기본값: 0.json— 쿼리 계획 단계를 JSON 포맷의 한 행으로 출력합니다. 기본값: 0. 불필요한 이스케이프를 피하려면 TabSeparatedRaw (TSVRaw) 포맷을 사용하는 것이 좋습니다.input_headers— 단계의 입력 헤더를 출력합니다. 기본값: 0. 주로 입력-출력 헤더 불일치와 관련된 문제를 디버깅하는 개발자에게만 유용합니다.column_structure— 헤더에서 컬럼의 이름과 유형뿐 아니라 구조도 함께 출력합니다. 기본값: 0. 주로 입력-출력 헤더 불일치와 관련된 문제를 디버깅하는 개발자에게만 유용합니다.distributed— 분산 테이블 또는 병렬 레플리카의 원격 노드에서 실행되는 쿼리 계획을 표시합니다.json과 함께는 지원되지 않습니다. 기본값: 0.compact— 활성화하면 계획에서 표현식 단계와 자세한 작업 정보(입력, 함수, aliases, 출력 위치)를 숨깁니다.actions = 1일 때만 효과가 있습니다. 기본값: 1.pretty— 들여쓰기 대신 선 그리기 문자(├──, └──, │)를 사용해 계층 구조를 시각화한 계획 트리를 출력합니다. 또한 조인 단계 속성을 인라인으로 포맷합니다. 기본값: 1.
기본적으로
explain_query_plan_default = 'pretty'이므로 actions, compact, pretty는 1로 초기화되며 계획은 compact, pretty, action 주석이 포함된 형태로 렌더링됩니다. EXPLAIN 문에서 이러한 옵션 중 하나를 명시적으로 지정하면(예: EXPLAIN actions = 0, compact = 0, pretty = 0 SELECT ...) 항상 기본값을 재정의합니다.ClickHouse 26.7 이전에는 actions, compact, pretty의 기본값이 0이었습니다. explain_query_plan_default = 'legacy'로 설정하거나(전역 또는 쿼리별 SETTINGS에서), compatibility를 26.7보다 이전 버전으로 설정하면 여전히 해당 출력을 얻을 수 있습니다.json 및 distributed 옵션은 explain_query_plan_default = 'pretty'인 경우에도 pretty 기본값(actions, compact, pretty)을 활성화하지 않습니다. 해당 출력에 action 세부 정보를 포함하려면 actions = 1을 수동으로 설정하십시오.단계별 비용 및 쿼리 비용 추정은 지원되지 않습니다.
json = 1이면 쿼리 계획이 JSON 포맷으로 표시됩니다. 모든 노드는 항상 Node Type, Node Id, Plans 키를 가지는 딕셔너리입니다. Node Type은 단계 이름을 나타내는 문자열이고, Node Id는 고유한 단계 식별자입니다(숫자 접미사가 붙은 단계 이름으로, 예: Union_10). Plans는 하위 단계 설명을 담은 배열입니다. 그 밖의 선택적 키는 노드 유형과 설정에 따라 추가될 수 있습니다.
예시:
description = 1이면 Description 키가 해당 단계에 추가됩니다:
header = 1이면 Header 키가 컬럼 배열 형태로 해당 단계에 추가됩니다.
예시:
indexes = 1이면 Indexes 키가 추가됩니다. 이 키에는 사용된 인덱스의 배열이 포함됩니다. 각 인덱스는 Type 키(문자열 Partition Min-Max, Partition, Statistics, PrimaryKey 또는 Skip)와 선택적 키를 포함하는 JSON으로 설명됩니다.
Statistics 인덱스는 파트별 컬럼 통계(최소/최대 값, 그리고 Nullable 컬럼의 NULL 값 개수)를 사용하여 쿼리 필터와 일치할 수 없는 파트를 건너뜁니다.
Name— 인덱스 이름입니다(현재는Skip인덱스에만 사용됩니다).Keys— 인덱스에 사용되는 컬럼 배열입니다.Condition— 사용된 조건입니다.Description— 인덱스 설명입니다(현재는Skip인덱스에만 사용됩니다).Parts— 인덱스 적용 전/후의 파트 수입니다.Granules— 인덱스 적용 전/후의 그래뉼 수입니다.Ranges— 인덱스 적용 후의 그래뉼 범위 수입니다.
projections = 1로 설정하면 Projections 키가 추가됩니다. 이 키에는 분석된 프로젝션의 배열이 포함됩니다. 각 프로젝션은 다음 키를 포함하는 JSON으로 설명됩니다:
Name— 프로젝션 이름입니다.Condition— 사용된 프로젝션 프라이머리 키 조건입니다.Description— 프로젝션이 어떻게 사용되는지에 대한 설명입니다(예: 파트 수준 필터링).Selected Parts— 프로젝션이 선택한 파트 수입니다.Selected Marks— 선택된 마크 수입니다.Selected Ranges— 선택된 범위 수입니다.Selected Rows— 선택된 행 수입니다.Filtered Parts— 파트 수준 필터링으로 건너뛴 파트 수입니다.
actions = 1로 설정하면, 추가되는 키는 단계 유형에 따라 달라집니다.
예시:
compact = 0과 actions = 1을 설정하면 Expression 단계와 함께 표현식에 대한 상세 정보를 확인할 수 있습니다:
distributed = 1로 설정하면 로컬 쿼리 계획뿐만 아니라 원격 노드에서 실행될 쿼리 계획도 출력에 포함됩니다. 분산 쿼리를 분석하고 디버깅할 때 유용합니다.
distributed는 pretty 출력이 원격 세그먼트의 계획을 계획 트리에 통합하지 않기 때문에 레거시(pretty가 아닌) 형식으로만 표시됩니다. 이러한 이유로 distributed를 활성화하면 explain_query_plan_default와 관계없이 pretty 기본값(actions, compact, pretty)이 자동으로 비활성화됩니다. 그래도 actions=1은 수동으로 설정할 수 있습니다. 또한 distributed 옵션은 json과 함께 사용할 수 없습니다.pretty = 1로 설정하면 들여쓰기 대신 선 그리기 문자를 사용하여 계획 트리가 표시되며, 주요 단계에 대한 추가 정보도 함께 표시됩니다:
- 쿼리 출력 컬럼은 플랜 상단에 표시됩니다.
- 필터, 집계 키, 정렬 설명, 윈도우 함수의 표현식은 사람이 읽기 쉬운 SQL 유사 표기법으로 표시됩니다(예:
greater(plus(a, 1), 5)대신a + 1 > 5). 명확성을 위해 내부 컬럼 식별자 프리픽스(예:__table1.)는 제거됩니다. - 소스 단계(
ReadFromMergeTree등)는 출력 컬럼을 표시합니다. - 필터 단계는 필터 조건을 SQL 표기법으로 표시합니다. 런타임 조인 필터가 있는 경우 별도로 표시됩니다.
- 집계 단계는 키와 해당 인수가 포함된 집계 함수를 표시합니다(예:
sum(c),count()). - 튜플 리터럴의 IN Set은 값을 표시하며(큰 Set의 경우 잘림), 서브쿼리 기반 Set에는
subquery1,subquery2등의 레이블이 지정되고,Set엔진 테이블의 Set은 테이블 이름을 표시합니다. - 조인 단계는 수학적 표기법을 사용한 조인 릴레이션, 조인 순서 최적화기가 해당 단계에 대해 산출한 추정치(비용, selectivity, 출력 행 수, 각 측의 행 수), 그리고 각 측의 입력 컬럼을 표시합니다. 다음 기호는 서로 다른 JOIN 유형을 나타내는 데 사용됩니다:
예를 들어
t1 ⟕ t2는 테이블 t1과 t2 간의 left join을 의미합니다.
테이블 이름 뒤의 대괄호 안 숫자(예: t1[100])는 테이블 STATISTICS를 사용할 수 있는 경우의
예상 행 수를 나타냅니다.
조인 릴레이션 아래에는 각 조인 단계마다 조인 순서 최적화기가 산출한 추정치가 표시됩니다:
Cost— 이 단계 아래에 있는 전체 조인 서브트리의 비용으로, 최적화기가 후보 join order를 비교할 때 최소화하려는 값입니다. 조인의 비용은 매칭된 행 쌍의 추정 개수인<selectivity> * <left_rows> * <right_rows>에 입력들의 비용을 더한 값입니다.Selectivity— 양쪽의 카테시안 곱 중 조인 조건을 통과하는 비율의 추정치입니다. 이는 join key의 distinct values 개수(NDV)로부터 도출됩니다. 키 동등 조건은 쌍 중 약1 / max(NDV_left, NDV_right)를 남기며, 조인 조건들 중 가장 작은 비율이 사용됩니다.Output rows— 조인이 생성하는 행 수의 추정치입니다. INNER JOIN의 경우<selectivity> * <left_rows> * <right_rows>이며,LEFT는<left_rows>,RIGHT는<right_rows>,FULL은<left_rows> + <right_rows>를 하한으로 합니다. OUTER JOIN은 보존되는 쪽의 모든 행을 유지하기 때문입니다.SEMI또는ANTI조인이 재정렬에 참여하는 경우, 보존되는 쪽의 일부 비율로 추정되는데,SEMI는<preserved_rows> * min(1, <selectivity> * <other_rows>)이고ANTI는 나머지 행입니다. 그 외의 경우에는 해당 조인 종류의 공식을 사용합니다.Left/Right— 각 쪽에서 조인으로 들어오는 행 수의 추정치입니다.
no stats로 보고됩니다. 이는 join order 최적화가
실행되지 않은 경우 — 예를 들어
query_plan_optimize_join_order_limit이
0인 경우 — 또는 추정할 근거가 없는 경우에 발생합니다.
Input (left): 및 Input (right): 줄은 각 쪽이 조인에 공급하는 컬럼을 나열합니다.
pretty 옵션은 Expression 단계와 상세한 action info를 숨기는 compact = 1과 함께 사용하면 플랜을 읽기 더 쉬워집니다.
조인을 포함한 상세 예시입니다.
join_runtime_filter_min_probe_rows
설정은 이처럼 작은 테이블에서도 런타임 조인 필터가 생성되도록 하기 위해서만 낮춘 것입니다:
EXPLAIN PIPELINE
설정:header— 각 출력 포트의 헤더를 출력합니다. 기본값: 0입니다.graph— DOT 그래프 기술 언어로 작성된 그래프를 출력합니다. 기본값: 0입니다.compact—graph설정이 활성화되면 그래프를 compact 모드로 출력합니다. 기본값: 1입니다.compact_repeated_processor_chains— 텍스트 출력에서 인접하게 반복되는 프로세서 체인을, 반복 횟수와 함께 체인 하나만 표시하는 방식으로 압축합니다. 예를 들어 조인에서 동일한 체인이 여러 번 나타나는 경우 병렬 파이프라인을 더 쉽게 읽을 수 있습니다. 그래프 출력에는 영향을 주지 않습니다. 기본값: 0입니다.
compact=0이고 graph=1이면 프로세서 이름에 고유한 프로세서 식별자를 나타내는 추가 접미사가 포함됩니다.
예시:
EXPLAIN ANALYZE
EXPLAIN ANALYZE는 실제로 쿼리를 실행하고 결과 행은 버린 다음, 각 간격에 실행 시 실제로 발생한 내용을 표시하여 EXPLAIN PLAN과 동일한 계획 트리를 출력합니다.
설정:
EXPLAIN ANALYZE는 EXPLAIN PLAN과 동일한 표시 옵션을 지원합니다(EXPLAIN PLAN 섹션에 설명되어 있음).
header— EXPLAIN PLAN 섹션을 참조하십시오.description— EXPLAIN PLAN 섹션을 참조하십시오.projections— EXPLAIN PLAN 섹션을 참조하십시오.sorting— EXPLAIN PLAN 섹션을 참조하십시오.input_headers— EXPLAIN PLAN 섹션을 참조하십시오.column_structure— EXPLAIN PLAN 섹션을 참조하십시오.actions— EXPLAIN PLAN 섹션을 참조하십시오. 기본값: 1.indexes— EXPLAIN PLAN 섹션을 참조하십시오. 기본값: 1.compact— EXPLAIN PLAN 섹션을 참조하십시오. 기본값: 1.pretty— EXPLAIN PLAN 섹션을 참조하십시오. 기본값: 1.processors—EXPLAIN ANALYZE에서는 각 스테이지마다 프로세서별 경과 시간 분포(min,median,max,sum)를 보여주는 추가 줄을 출력합니다. 병렬 프로세서 간 부하 편차를 파악하는 데 유용합니다. 기본값: 0.matches—EXPLAIN ANALYZE에서는 조인 결과만으로 해당 수치를 도출할 수 없는 경우matched,match rate,fanout메트릭에 필요한 추가 기록 작업을 조인 간격에서 수행합니다. 도출할 수 있는 경우에는 이 옵션 없이도 보고됩니다. 조인 간격을 참조하십시오. 기본값: 0.time—EXPLAIN ANALYZE에서는 간격별로Time및Concurrency줄을 출력하여 해당 간격과 그 브랜치의 실제 경과 시간 및 동시성(Concurrency) 수준을 보여줍니다. 간격 및 브랜치의 실제 경과 시간과 동시성 수준을 참조하십시오. 기본값: 1.
EXPLAIN ANALYZE는 감싼 쿼리를 실제로 실행하므로, 여러 측면에서
실행하지 않는 EXPLAIN 형식과는 달리 해당 쿼리와 동일하게 동작합니다:- 쿼터와 제한. 직접 쿼리를 실행할 때와 동일한 쿼터가 적용되며,
동일한 제한
(예:
query_selects,read_rows)의 적용을 받습니다. 계획 수립 중 쿼터가 면제되는 소스 (예:system.one)에는 과금되지 않습니다. - 실패한 트랜잭션. 이미 실패한(
ROLLED_BACK) 트랜잭션 내부에서는 일반SELECT와 마찬가지로INVALID_TRANSACTION과 함께 거부되므로, 먼저ROLLBACK을 실행하십시오. - 스트리밍 읽기. 스트리밍(
FROM ... STREAM) 읽기에서는 해당 읽기가 끝나지 않기 때문에NOT_IMPLEMENTED와 함께 거부됩니다. - 분산 쿼리. 분산 모드에서 실행되는 쿼리에는 지원되지 않습니다.
Time— 총 시간이며, 계획 단계(즉, 계획 생성 + 계획 최적화 + 파이프라인 구성)와 실행 단계(파이프라인 실행)로 나뉩니다.Execution—time = 0이면 표시되지 않습니다. 실행 시간을in steps,outside steps,idle로 나누어 보여줍니다. 각 항목의 합은execution과 같습니다. 간격과 브랜치의 실제 경과 시간 및 동시 실행 수준을 참조하세요.Read— 테이블에서 읽은 행 수와 비압축 바이트 수이며, 처리량이 함께 표시됩니다. 이는 일반 쿼리 footer에 “Processed”로 표시되는 것과 동일한 수치입니다.Peak memory— 쿼리가 사용한 최대 메모리입니다.
I/O 줄). 시간과 병렬성은 간격의 각 스테이지별로 다음 들여쓴 줄에 표시됩니다.
rows <in> → <out>— 간격에 들어온 행 수와 간격을 빠져나간 행 수입니다. (<selectivity>%)는 간격이 데이터를 얼마나 필터링했는지(out/in) 또는 확장했는지를 보여주며, 입력 행 수와 출력 행 수가 같거나 입력 행 수가0일 때는 표시되지 않습니다.<bytes_in> → <bytes_out>— 간격을 통과하는 비압축 인메모리 바이트 수입니다(둘 다 0이면 생략됨).time <t> (<share>%)— 해당 스테이지가 활성 상태였던 실제 경과 시간(wall-clock time)과 쿼리 실행 시간에서 차지하는 비율입니다(즉, build 시간 제외). 스테이지와 간격은 동시에 실행될 수 있으므로 비율의 합이 100%를 초과할 수 있습니다.parallelism <avg>/<max>— 이 스테이지 내에서 동시에 작업한 CPU 스레드의 평균 수와, 사용할 수 있었던 최대 수입니다. 이 메트릭은 해당 스테이지만 대상으로 하므로, 동시에 쿼리의 다른 간격에서 작업하는 스레드는 포함하지 않습니다. 값이 최대치에 가까우면 해당 스테이지가 잘 병렬화되었음을 의미하고, 1에 가까우면 대부분 직렬로 실행되었음을 의미합니다.Stage (<stage>)— 스테이지의 이름입니다. 스테이지가 하나뿐인 간격은Stage (...)레이블 없이 시간 줄을 직접 출력합니다. 여러 스테이지가 있는 간격은 스테이지마다 레이블이 붙은 줄을 하나씩 출력합니다. 예를 들어Aggregating은Stage (partial aggregation)과Stage (final aggregation)을 표시하고, 해시 조인은Stage (build)와Stage (probe)를 표시합니다.
ClickHouse는 계획 간격 내 작업의 실행뿐 아니라 계획 간격 자체의 실행도 병렬화합니다.
parallelism 메트릭은 이 간격의 작업만 반영합니다. 다른 간격도 동시에 실행될 수 있으므로, 이 수치만으로는 해당 간격의 병렬성이 전체 쿼리와 비교해 어느 정도인지는 알 수 없습니다. 쿼리 전체의 동시성을 확인하려면 time = 1과 함께 표시되는 Concurrency 메트릭을 참조하십시오(계획 간격과 브랜치의 실제 경과 시간 및 동시성 수준).parallelism의 최대값은 다음 두 값 중 최솟값으로 계산됩니다.- 계획 간격 내 전체 작업 수
max_threads에 설정된 최대 쿼리 처리 스레드 수
조인 단계
조인 단계에서EXPLAIN ANALYZE는 조인 순서 최적화기의 추정치와 실제 결과를 비교하는 행(추정 조인 메트릭과 실제 조인 메트릭 비교 참고)과 각 측의 참여 행인 Left와 Right를 출력한 후, 조인 구현에 특화된 행을 출력합니다. Left와 Right는 SQL상의 논리적인 측에 해당합니다. 대부분 Left는 조인의 프로브(probe) 측이기도 하며, Right는 조인의 빌드(build) 측이기도 합니다. 그러나 조인 실행 중에 스왑이 발생할 수 있으므로 항상 그런 것은 아닙니다. join_algorithm의 모든 값(hash, parallel_hash, grace_hash, partial_merge, full_sorting_merge, parallel_full_sorting_merge, direct)이 지원됩니다. 또한 이 설정으로 선택할 수 없는 세 가지 구현, 즉 CROSS 또는 COMMA 조인, 조인 키를 결정하지 않는 ON 절을 사용하는 블록 중첩 루프 조인(block nested loop join), 그리고 Join 테이블 엔진도 지원됩니다. 대부분은 양쪽 모두에 대한 정보를 보고하지만, 일부는 구체화하는 측에 대해서만 보고합니다(예: direct는 Left:만 출력합니다).
각 측의 행은 동일한 형식을 따릅니다:
EXPLAIN ANALYZE는 다음을 보고합니다.
rows estimated <estimated_rows>— 조인 순서 최적화기가 추정한 해당 측면의 행 수이며, 옆에 표시되는 실제rows와 비교할 수 있도록 출력됩니다. 최적화기가 추정치를 산출하지 못한 경우no stats로 표시됩니다(추정 조인 메트릭과 실제 조인 메트릭 참조).rows <rows>— 해당 측면에서 조인을 거친 전체 행 수입니다.matched <matched_rows>— 반대 측면에서 하나 이상의 조인 파트너와 일치한 해당 측면의 행 수입니다. 키가 아닌 행을 계산합니다. 예를 들어 키가 오른쪽에 세 번 나타나 일치하는 경우, 오른쪽의 세 행 모두 일치한 것으로 계산됩니다.match rate <match_rate>%— 해당 측면에서 일치한 행의 비율이며,100 * <matched_rows> / <rows>로 계산됩니다.fanout <fanout>— 해당 측면에서 일치한 행 하나당 평균적으로 생성된 출력 행 수입니다.
0이 아니라 not collected로 보고됩니다. match rate와 fanout은 matched에서 산출되므로, matched가 없는 측면에서는 세 항목 모두 not collected로 보고됩니다.
추정 조인 메트릭과 실제 조인 메트릭
조인 단계에는 조인 순서 최적화기의 추정치가 담기며, 이는EXPLAIN PLAN이 보여주는 값과 동일합니다(EXPLAIN PLAN 섹션 참조). EXPLAIN ANALYZE는 이러한 추정치를 각각 실제 측정값과 나란히 출력합니다:
Cost— 두 값 모두 매칭된 출력 행 수를 기준으로 합니다. 추정값은 조인 서브트리에 대한 최적화기의 비용으로,<selectivity> * <left_rows> * <right_rows>에 그 입력들의 비용을 더한 값입니다. 실제 값도 같은 방식으로 측정됩니다. 즉, 이 조인의 매칭된 출력 행 수에 동일한 재정렬 cluster에 속하는 하위 조인들의 실제 비용을 모두 더한 값입니다.Selectivity— 추정값은 조인 키의 distinct values 개수로부터 도출되며, 실제 값은 데카르트 곱 중 실제로 출력에 남은 비율을 측정한<matched output rows> / (<left rows> * <right rows>)입니다. 최적화기가 추정하려는 대상이 바로 이 값이기 때문입니다.Output rows— 조인이 생성한 행 수의 추정값과 실제 값입니다. 두 값이 모두 0이 아니면q-error로max(estimated / actual, actual / estimated)가 보고되며, 이는 cardinality 추정 품질을 나타내는 표준 척도입니다.1.00은 추정이 완벽했음을 의미하고, 값이 클수록 최적화기가 크게 빗나간 cardinality를 근거로 조인 순서를 선택했다는 뜻입니다.
no stats로 보고됩니다. 예를 들어 query_plan_optimize_join_order_limit가 0이어서 조인 순서 최적화가 실행되지 않은 경우가 여기에 해당합니다. 이는 실행 과정에서 측정할 수 없었던 실제 값을 표시하는 not collected와는 다릅니다. 오른쪽이 미리 채워진 조인(Join 테이블 엔진, direct 조인)은 조인 순서 최적화기를 거치지 않으므로 참여 라인만 출력합니다.
조인 단계은 양쪽에서 조인으로 전달되는 컬럼을 보여주는 Input (left): 및 Input (right): 라인도 함께 출력합니다.
EXPLAIN PLAN 조인 예시의 테이블을 대상으로 하면, EXPLAIN ANALYZE SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.id의 조인 단계은 다음과 같습니다:
팬아웃
fanout은 행이 얼마나 늘어나는지를 측정합니다:
NULL로 채워진 출력 행을 하나 생성합니다. 이러한 행은 비율을 왜곡하지 않도록 제외합니다. 이러한 행은 보존 측에만 존재합니다. 즉, RIGHT 및 FULL에서는 오른쪽 측에, LEFT 및 FULL에서는 왼쪽 측에 존재합니다.
fanout = 0— 일치한 행이 출력 행을 전혀 생성하지 않았습니다. 이는ANTI조인의 동작으로, 상대 행을 찾지 못한 행만 출력합니다.fanout = 1— 깔끔한 1:1 조인으로, 일치한 각 행이 정확히 하나의 출력 행을 생성했습니다.fanout > 1— 1:N 조인으로, 반대쪽의 중복 key로 인해 행 수가 늘어났습니다. 양쪽에서 동시에 큰 값이 나타나면 의도하지 않은 데카르트 곱 폭증의 징후입니다.
수치에 matches = 1이 필요한 경우
이러한 수치 대부분은 조인이 어차피 생성하는 데이터로부터 산출되며, 일반 EXPLAIN ANALYZE로 보고됩니다. 나머지는 조인이 그렇지 않으면 수행하지 않을 추가 기록 작업이 필요하므로 EXPLAIN ANALYZE matches = 1에서만 보고됩니다. 어떤 수치가 이에 해당하는지는 알고리즘에 따라 달라지며, 해시 계열에서는 다음 두 가지입니다.
- 일치하는 모든 오른쪽 행을 표시해야 하는
ALL INNER및ALL LEFT의 오른쪽 - 쿼리가 오른쪽 테이블에서 아무것도 선택하지 않고
ON절이 단순한 키 동등 조건인 경우에만 해당하는ALL LEFT및ALL FULL의 왼쪽. 그렇지 않으면 프로브에서 이미 어떤 왼쪽 행이 일치했는지 기록합니다. 이는 오른쪽 컬럼을 구체화하거나 잔여 조건을 평가하기 위해 필요하므로, 옵션 없이도 개수가 정확합니다.
partial_merge는 같은 이유로 네 가지 ALL 유형의 오른쪽에 이를 필요로 합니다.
full_sorting_merge와 parallel_full_sorting_merge는 ANY 유형의 양쪽에 이를 필요로 합니다. ALL
유형에는 아무것도 필요하지 않습니다.
추가 기록 작업은 비용이 발생하므로 이 옵션은 기본적으로 꺼져 있으며, 이는 측정 정확도를 위해 치르는 비용입니다. 작업은 프로브 루프 내에서 수행되며 출력 행 수에 따라 증가합니다. 왼쪽 및 오른쪽 행이 반대편에서 찾은 정확한 일치 수를 확인해야 할 때
matches = 1을 사용하십시오.matches = 1을 사용해도 모든 조합의 수치를 수집할 수 있는 것은 아닙니다. 조인이 어느 쪽을 보고할 수 있는지는
해당 조인이 어차피 수행해야 하는 작업에 따라 결정되므로, 유형과
엄격성뿐 아니라 알고리즘에도 따라 달라집니다.
해시 계열. hash, parallel_hash, grace_hash는 항상 서로 동일하게 동작합니다.
ANY, SEMI, ANTI 조인은 해시 테이블에 키당 하나의 행만 유지하므로 오른쪽 수치를 사용할 수 없습니다. 중복된 오른쪽 행은 저장되지 않으므로 개수를 셀 수도 없습니다. 다른 왼쪽 행이 이미 상대 행을 차지해 왼쪽 행의 출력을 억제하는 조인에서는 왼쪽 수치를 사용할 수 없습니다. 이 경우 출력된 행 수는 일치한 행 수보다 적게 집계됩니다.
any_join_distinct_right_table_keys를 활성화하면 ANY가 이전 RightAny 의미 체계로 전환됩니다. 이 의미 체계는 왼쪽 행마다 하나의 행을 출력하므로 양쪽 개수를 모두 유지합니다. 그러면 ANY RIGHT와 ANY FULL은 양쪽을 모두 보고하고, ANY INNER는 SEMI LEFT로 재작성됩니다.
Join 테이블 엔진도 엔진에 선언된 유형과 엄격성을 사용하여 동일한 표를 따릅니다. Join(ALL, INNER, …)는 양쪽을 보고하고, Join(ANY, LEFT, …)는 어느 쪽도 보고하지 않습니다.
머지 알고리즘. full_sorting_merge와 parallel_full_sorting_merge는 네 가지 ALL 유형, ANY INNER, ANY LEFT, ANY RIGHT, ASOF, ASOF LEFT를 지원합니다. ASOF와 ASOF LEFT를 제외한 모든 유형에서 양쪽을 보고합니다. ASOF와 ASOF LEFT에서는 오른쪽이 not collected입니다. 또한 matches = 1 없이도 가능합니다. 두 정렬된 입력을 순회하며 동일한 범위를 소비할 때 모든 행을 확인하므로 나중에 재구성할 필요가 없습니다.
partial_merge는 ALL INNER, ALL LEFT, ALL RIGHT, ALL FULL, ANY INNER, ANY LEFT, SEMI LEFT를 지원합니다. 네 가지 ALL 유형에서는 양쪽을 보고하며, 오른쪽에는 matches = 1이 필요합니다. ANY INNER, ANY LEFT, SEMI LEFT에서는 오른쪽이 not collected입니다.
direct. 왼쪽만 해당합니다. 오른쪽은 행으로 구체화되지 않는 키-값 저장소이므로 Right: 줄 자체가 없습니다.
CROSS, COMMA 및 상수 ON. 위에 설명한 대로 어느 쪽도 해당하지 않습니다.
블록 중첩 루프 조인(Block nested loop join). 조인 키를 결정하지 않는 ON 절을 받는 연산자입니다. 단, 그보다 앞선 경로 중 하나가 해당 조건을 먼저 가져가는 경우는 예외입니다(allow_block_nested_loop_join 참조). 이 연산자는 ASOF, PASTE, ANY FULL을 제외한 모든 조인 종류와 엄격성을 지원합니다.
연산자가 어떤 왼쪽 행이 매칭되었는지 이미 기록하고 있다면, 옵션 없이도 왼쪽이 보고됩니다. 매칭되지 않은 왼쪽 행을 유지하는 모든 조인 종류에는 이 기록이 필요하며, 왼쪽 행당 최대 하나의 쌍만 취하는 모든 엄격성도 마찬가지입니다. 오른쪽은 연산자가 매치 플래그를 유지하는 경우에 보고되며, 이 플래그는
RIGHT, FULL 및 오른쪽 기준의 SEMI/ANTI에 필요합니다. ANY INNER도 플래그를 유지하지만, 이는 오른쪽 행을 하나의 왼쪽 행에만 할당하기 위해서일 뿐입니다. 이미 쌍이 정해진 왼쪽 행에 대해서는 더 이상 매칭을 시도하지 않으므로, 플래그는 모든 매치가 아니라 결과에 포함된 쌍만 표시하며, 따라서 보고되지 않습니다. ALL INNER는 hash가 비활성화된 경우에만 이 연산자로 처리됩니다. 그렇지 않으면 해당 조건은 필터가 적용된 CROSS JOIN으로 변환되기 때문입니다.
any_join_distinct_right_table_keys를 활성화하면 여기에서도 ANY가 RightAny 의미 체계로 전환됩니다. 이때 왼쪽은 모든 조인 종류에서, 오른쪽은 RIGHT와 FULL에서 보고되며, ANY INNER는 SEMI LEFT로 재작성됩니다.
두 알고리즘이 모두 수치를 보고하는 경우 그 수치는 서로 일치합니다. 머지 알고리즘은 더 많은 정보를 가질 뿐, 무엇을 매치로 간주하는지는 동일합니다.
알고리즘별 행
각 조인 구현에서 앞서 설명한 내용에 추가되는 행을 살펴보겠습니다.hash 및 parallel_hash 조인과 Join 테이블 엔진에서는 Hash table: 행이 오른쪽 테이블을 기반으로 구축된 해시 테이블을 설명합니다:
unique keys <unique_keys>— 빌드 스테이지에서 해시 테이블에 저장된 고유 키 수입니다.memory <peak_memory>— 빌드 스테이지에서 해시 테이블이 사용한 최대 메모리입니다.
grace_hash 조인에서는 Hash table: 줄에 조인이 메모리 제한에 맞춰 조정된 방식도 추가로 표시되며, Spill: 줄에는 데이터가 디스크에 기록되었는지가 표시됩니다:
buckets <buckets>— 실행이 끝날 때 grace hash 조인에서 사용된 버킷 수입니다. 항상2의 거듭제곱입니다.rehashes <rehashes>— 메모리 제한에 맞추기 위해 버킷 수를 2배로 늘린 횟수입니다.Spill:— 디스크 스필 발생 여부를 나타내는yes/no플래그입니다. 스필이 발생한 경우left spilled <left_spilled_bytes>및right spilled <right_spilled_bytes>는 왼쪽(probe)과 오른쪽(build) 측에서 스필된 압축 바이트 수를 표시합니다. 스필이 발생하지 않은 경우에는 해당 줄이Spill: no로 표시됩니다.
partial_merge 조인의 경우 Right: 줄에는 오른쪽 테이블의 버퍼링 및 정렬 방식에 관한 추가 정보가 포함되며, 정렬 시간은 Stage (build) 및 Stage (probe) 줄에 표시됩니다:
size <right_size>— 오른쪽 테이블 블록의 메모리 크기입니다.blocks <right_blocks>— 오른쪽 테이블이 버퍼링된 블록 수입니다.storage <in-memory|external>— 오른쪽 테이블이 메모리에 들어갔는지(in-memory), 아니면 디스크로 스필되었는지(external)를 나타냅니다.external인 경우 추가로spilled <spilled_bytes>가 디스크에 기록된 압축 바이트 수를 표시합니다.sort time <sort_time>— 오른쪽 테이블을 정렬하는 데 소요된 시간(빌드 스테이지)과 들어오는 각 왼쪽 블록을 정렬하는 데 소요된 시간(프로브 스테이지)입니다.sort share <sort_share>%— 스테이지time백분율은 전체 쿼리의 실행 시간에서 차지하는 비율인 반면, 이는 해당 스테이지의 자체 작업 시간(프로세서 경과 시간의 합)에서sort time이 차지하는 비율입니다.
full_sorting_merge 조인에서는 공통된 Left: 및 Right: 줄만 출력됩니다.
direct 조인에서는 오른쪽이 행으로 구체화되지 않고 직접 조회되는 키-값 저장소이므로 Left: 줄만 출력됩니다.
CROSS 또는 COMMA 조인과, ON 절에 키 동등 조건이 없는 ALL INNER JOIN(플래너가 해당 조건을 필터로 적용하는 CROSS JOIN으로 변환함)에서는 Buffer: 줄이 오른쪽 테이블이 메모리에 보관된 방식을 설명하고, Spill: 줄이 디스크로 스필되었는지를 표시합니다:
memory <peak_memory>— 버퍼링된 오른쪽 테이블이 점유한 최대 메모리입니다.compressed <yes|no>— 버퍼링된 블록 중 하나 이상이 압축되었는지 나타냅니다. 압축된 블록이 하나라도 있으면 리더는 저장된 모든 블록의 압축을 해제합니다.Spill:—grace_hash와 동일한yes/no플래그이며,right spilled <right_spilled_bytes>는 디스크에 기록된 압축 후 바이트 수를 보고합니다.
matched not collected를 보고합니다. 상수 프레디케이트는 모든 왼쪽 행을 모든 오른쪽 행과 매칭하거나 전혀 매칭하지 않으므로, 개별 행 중 어떤 행이 매칭되었는지 확인할 방법이 없습니다.
키 동등 조건이 없는 나머지 ON 절을 모두 처리하는 블록 중첩 루프 조인(block nested loop join)도 자신이 구체화하는 오른쪽 테이블에 대해 동일한 두 줄을 출력합니다:
memory <peak_memory>— 저장된 오른쪽 테이블이 차지한 최대 메모리입니다. 모든 블록이 도착하는 즉시 디스크에 기록되었다면 어떤 블록도 메모리에 보관된 적이 없으므로0입니다.compressed <yes|no>— 저장된 블록 중 하나 이상이 압축되었는지 여부입니다. 압축된 경우 리더는 저장된 모든 블록의 압축을 해제합니다.Spill:—grace_hash와 동일한yes/no플래그이며,right spilled <right_spilled_bytes>는 디스크에 기록된 압축 바이트 수를 나타냅니다.
CROSS와 달리 여기서는 연산자가 검사하는 각 쌍에 대해 실제 조건을 평가하므로 양쪽 모두 matched를 표시할 수 있습니다. 어느 쪽이 표시하는지는 위의 표를 참고하십시오.
Join 테이블 엔진을 대상으로 조인을 수행하면 사전 구축된 테이블을 설명하는 Hash table: 줄과 함께 양쪽 정보가 모두 표시됩니다. 오른쪽은 쿼리별 빌드의 행 수가 아니라 엔진에 저장된 행 수를 나타냅니다.
프로세서별 시간
processors = 1인 경우 각 스테이지 아래에 추가 줄이 출력되며, 해당 스테이지의 프로세서 전반에 걸친 경과 시간 분포를 보여줍니다.
<n>은 해당 단계에 있는 프로세서의 수입니다. median과 max 사이의 큰 차이는 병렬 프로세서 간의 부하 편차를 나타냅니다.
간격 및 분기별 실제 경과 시간과 동시성 수준
time = 0으로 설정하지 않았다면 쿼리 계획의 각 간격에 2줄이 추가로 출력됩니다.
step은 간격 자체를 의미합니다. branch는 해당 간격을 루트로 하는 하위 트리, 즉 해당 간격과 계획에서 그 아래에 있는 모든 간격을 합친 것을 의미합니다.
Time— 간격(step) 또는 하위 트리에 속한 간격 중 하나(branch)에 대해 하나 이상의 스레드가 작업을 수행한 실제 경과 시간(wall-clock time)입니다.<share>는 이 시간을 쿼리 실행 시간에 대한 백분율로 나타낸 값입니다.Concurrency— 간격(step) 또는 그 하위 트리(branch)가 활성 상태인 동안 해당 간격뿐 아니라 쿼리의 모든 간격에서 작업 중이던 스레드의 평균 개수입니다.<m>은 쿼리가 사용할 수 있는 최대 스레드 수입니다. 프로세서를 소유하지 않는 간격(예: 입력이 이미 동일한 헤더를 가진Union)은 측정할 작업이 없으므로step에Unknown을 출력합니다. 이때도branch는 보고됩니다.
Time은 해당 간격 인터벌들의 합집합 길이입니다. 어떤 스레드도 해당 간격에서 작업하지 않은 공백 구간은 포함되지 않습니다. 브랜치의 Time은 하위 트리에 속한 모든 간격의 인터벌을 먼저 합친 뒤 계산합니다.
루트 간격의 branch는 전체 계획에 해당하지만, 그 비율은 보통 100%보다 낮습니다. 나머지 실행 시간이 어디에 쓰였는지는 쿼리 요약의 Execution 줄에서 확인할 수 있습니다(위 예시의 쿼리 요약 참조).
in steps— 계획에 속한 모든 간격 인터벌의 합집합입니다. 이는 루트 간격의branch시간과 같으며, 비율도 동일합니다.outside steps— 하나 이상의 스레드가 프로세서를 실행했지만 그중 어느 것도 이 계획의 간격에 속하지 않은 시간입니다. 출력 싱크,Resize, 형식 변환용 변환(transform), 이 계획에서 연결할 수 없는 다른 계획의 간격이 여기에 해당합니다.idle— 어떤 스레드도 프로세서를 실행하지 않은 시간입니다. 실행기의 시작 및 종료 과정, 모든 스레드가 대기하던 순간이 여기에 해당합니다.
Time 비율, 스테이지별 time 비율, Execution 비율은 모두 같은 분모를 사용하므로 서로 비교할 수 있습니다.
Concurrency는 해당 합집합 구간 안에서 모든 쿼리 스레드가 작업한 총 시간을 합집합의 길이로 나눈 값입니다. 스테이지 자체의 스레드만 집계하는 스테이지별 parallelism 메트릭과 달리, 쿼리의 모든 간격에서 작업 중인 스레드를 집계합니다. 즉, “이 간격(브랜치)이 활성 상태인 동안 쿼리 전체가 얼마나 바빴는가?”를 나타냅니다. 값이 <m>에 가까우면 해당 간격이 실행되는 동안 쿼리가 완전한 병렬 상태를 유지했다는 뜻입니다. 값이 1에 가까우면 그동안 쿼리가 직렬화되었다는 뜻입니다. step에서는 작업 중이던 단일 스레드가 이 간격 자체를 처리하고 있었으므로 이 간격이 직렬화 지점이 됩니다. 반면 branch에서는 스레드가 하위 트리 어딘가에서 작업하고 있었을 뿐, 반드시 이 간격을 처리했던 것은 아닙니다. 직렬화된 간격은 Time 비율도 높을 때에만 실제 병목 지점이 됩니다.
EXPLAIN ESTIMATE
쿼리를 처리하는 동안 테이블에서 읽게 될 것으로 예상되는 행 수, 마크 수, 파트 수를 표시합니다. MergeTree 계열 테이블에서 동작합니다. 예시 테이블 생성:Query
Query
Response
EXPLAIN WHATIF
가상 스킵 인덱스를 디스크에 구체화하지 않고 해당 인덱스가SELECT 쿼리에 얼마나 도움이 될지 추정합니다. CREATE HYPOTHETICAL INDEX로 후보를 하나 이상 정의한 다음 EXPLAIN WHATIF SELECT ...를 실행하면 후보별 적용 가능 여부, 예상 읽기 마크 수, 예상 바이트 수, 스킵 비율을 확인할 수 있습니다.
CREATE HYPOTHETICAL PROJECTION으로 정의한 가상 프로젝션도 후보에 포함됩니다. 일반 프로젝션은 쿼리가 읽을 파트를 대상으로 메모리에 프라이머리 인덱스를 구축하고, 구체화된 프로젝션과 같은 방식으로 프루닝하여 추정합니다.
보고서에는 프로젝션이 읽을 마크와 행의 수, 기반 테이블(base table)을 읽을 때와 비교한 read_ratio, 최적화기가 해당 프로젝션을 선택할지에 대한 verdict가 표시됩니다. force_optimize_projection = 1 또는 prefer_optimize_projection = 1이 설정되면 최적화기는 사용 가능한 모든 프로젝션을 사용하므로, 비용 기준으로는 선택되지 않을 프로젝션도 chosen (forced)로 보고됩니다.
결과가 프로젝션 파트의 구성 방식에 따라 달라지는 경우 marks_span에 범위가 표시되며, 어느 쪽으로든 결정될 수 있는 판단은 too close to call로 보고됩니다. 대용량 테이블에서는 그래뉼의 표본을 읽어 추정합니다(projection_scan_budget_rows 참고).
집계 프로젝션, WHERE 절이나 자체 스킵 인덱스가 있는 프로젝션, 커밋 순서 키나 가상 컬럼 키를 사용하거나 _block_number를 저장하는 프로젝션, 쿼리가 읽는 컬럼을 모두 포함하지 않는 프로젝션은 not_applicable로 보고됩니다. force_optimize_projection_name과 preferred_optimize_projection_name은 무시되며, force_optimize_projection이 설정되어도 SQL 문이 실패하지 않습니다.
구문
projection_scan_budget_rows— 프로젝션을 추정할 때 그래뉼 샘플링으로 전환하기 전까지 읽을 수 있는 최대 행 수입니다. 기본값:10000000.0은 제한이 없음을 의미하며,max_rows_to_read로 이 값을 낮출 수 있습니다. 샘플링 시에는 최소 약 30개의 그래뉼과 파트당 1개의 그래뉼을 읽으며,max_rows_to_read가 이를 허용하지 않으면 추정 결과는unsupported가 됩니다.empirical—1(기본값)은 기준 프루닝 후 남은 그래뉼에 인덱스를 메모리상에서 적용해 스킵 비율의 상한을 측정합니다.0은 이 단계를 건너뜁니다. 어느 쪽이든 경험적 평가로 결과를 얻지 못하면(비활성화되었거나 인덱스를 메모리에서 평가할 수 없는 경우) 추정기는 컬럼 통계로 폴백합니다. 컬럼 통계도 사용할 수 없으면 적용 가능 여부만 요약합니다.
source— 추정치가 산출된 방식입니다.empirical: 기준선 프루닝이 적용된 그래뉼을 기준으로 메모리에서 인덱스를 구축한 뒤, 해당 인덱스가 건너뛸 그래뉼 수를 계산했습니다. 이는 상한값입니다. 자세한 내용은CREATE HYPOTHETICAL INDEX의 제한 사항을 참조하십시오.statistical: 컬럼 통계를 바탕으로 도출됩니다. empirical이 비활성화된 경우(empirical = 0) 또는 empirical이 결과를 산출하지 못했고 관련 컬럼에 컬럼 통계가 정의되어 있을 때 사용됩니다.applicability_only: 인덱스는 프레디케이트에 적용할 수 있지만 경험적 추정과 statistical 추정 모두 결과를 산출하지 못한 경우입니다(예:empirical = 0이고 컬럼 통계가 정의되지 않은 경우). 보수적인 상한값으로skip_ratio: 0.0%를 보고합니다.
empirical_reason— 경험적 추정을 실행할 수 없는 이유입니다.empirical_status: unsupported일 때만 표시됩니다. 예를 들어merge_tree_min_rows_for_seek또는merge_tree_min_bytes_for_seek가 0이 아니면 실제 읽기에서 마크 범위가 병합되지만, 그래뉼별 개수는 이를 모델링하지 않으므로 추정치는statistical또는applicability_only로 대체됩니다.sampled_parts/sampled_marks—<baseline-pruned> / <total in the table>. 테이블에서 PK, 파티션, 기존 인덱스 프루닝을 거친 뒤 남은 비율, 즉 가상 인덱스의 입력이 되는 범위를 보여줍니다. 프로젝션의 경우sampled_marks는<marks read> / <marks in the parts the query reads>이며, 첫 번째 숫자가 두 번째 숫자보다 작으면 추정에 샘플을 사용했음을 의미합니다.est_bytes— 읽기 바이트 수의 추정치입니다. 테이블의 평균 행 크기를 바탕으로 계산하므로 근사치이며, 스토리지와 압축에 따라 달라집니다. 기준선 행은 쿼리가 행을 읽을 때만 표시되며, 각 후보 행은 기준선 바이트 추정치를 알 수 있을 때만 표시됩니다.
WHATIF와 SELECT 사이에 인라인으로 작성하며, SETTINGS keyword는 없습니다(다른 EXPLAIN 변형이 옵션을 받는 방식과 동일합니다).
테이블에 가상 인덱스와 가상 프로젝션이 모두 정의되어 있지 않으면 EXPLAIN WHATIF는 status: not_applicable와 함께 생성하라는 힌트를 보고합니다.
결합 행(여러 후보)
두 개 이상의 후보를 경험적으로 평가하면 EXPLAIN WHATIF는 후보별 행 뒤에 (combined: idx_a, idx_b, ...)라는 블록을 하나 더 추가합니다. 이 블록은 해당 인덱스를 모두 함께 사용할 때 얻는 효과를 보여줍니다. 실제 읽기에서는 그래뉼이 모든 스킵 인덱스를 통과해야 남으므로, 결합 추정치는 각 후보를 통과한 그래뉼의 교집합을 바탕으로 합니다. 따라서 skip_ratio는 가장 효과적인 단일 후보의 비율 이상입니다. 서로 보완하는 인덱스를 함께 사용하면 더 많은 그래뉼을 프루닝할 수 있지만, 중복되는 인덱스는 비율을 바꾸지 않습니다.
결합 행은 후보별로 살아남은 그래뉼 집합의 교집합을 바탕으로 하므로 source: empirical인 후보만 반영됩니다. statistical 또는 applicability_only로 추정된 후보에는 그래뉼별 데이터가 없어 제외됩니다. 따라서 경험적 추정치가 산출된 후보가 두 개 이상일 때만 결합 블록이 표시되며, 그렇지 않으면 생략됩니다(예: empirical = 0인 경우). 추정 필드는 후보별 경험적 추정 블록과 같지만, elapsed_us는 0입니다. 결합 추정치는 새로 스캔하지 않고 후보별 스캔 결과에서 도출하기 때문입니다. (combined: ...)라는 이름은 보고서에만 사용되는 레이블이며 force_data_skipping_indices에는 사용할 수 없습니다.
경험적 예시
minmax는 마크 100개를 1개로 프루닝하며, 스킵 비율은 skip_ratio: 99.0%입니다. (est_bytes는 평균 행 크기를 바탕으로 한 추정치이므로 정확한 값은 달라질 수 있습니다.)
통계 예시
컬럼 통계는 기본적으로 비활성화되어 있습니다. statistical 경로를 테스트하려면 먼저 관련 컬럼에 이를 정의하고 구체화 mutation이 완료될 때까지 기다리십시오:
b < 10의 컬럼 통계 선택도(selectivity)에서 나오며(10000개 행 중 약 10개 행), skip_ratio의 상한값으로 보고됩니다. sampled_parts / sampled_marks는 없으며, 데이터를 읽지 않았습니다.
두 경로 모두 사용할 수 없으면(예: empirical = 0이고 컬럼 통계가 정의되지 않은 경우), 추정기는 source: applicability_only와 보수적인 skip_ratio: 0.0%를 보고합니다.
가상 프로젝션
일반 프로젝션은 기본 키와 파티션 프루닝을 거친 뒤 쿼리가 읽을 파트를 대상으로 동일한 방식으로 추정됩니다:
marks와 rows는 기반 테이블을 읽을 때의 비율이 아니라 프로젝션을 읽을 때 실제로 접근하는 마크와 행을 나타냅니다. 프로젝션 그래뉼에는 기반 테이블 그래뉼과 다른 행이 들어 있기 때문입니다. read_ratio는 프로젝션의 마크 수를 기반 테이블의 마크 수로 나눈 값으로, 0.02x는 읽기 작업량이 50배 적고 15x는 15배 많다는 뜻입니다. verdict는 최적화기의 선택 기준을 적용합니다 — 기반 테이블보다 마크 수가 적거나, 프로젝션이 쿼리의 ORDER BY를 충족하면서 마크 수가 같아야 합니다. 따라서 후보가 applicable이어도 선택되지 않을 수 있습니다.
EXPLAIN TABLE OVERRIDE
테이블 함수를 통해 접근한 테이블 스키마(schema)에 테이블 재정의를 적용한 결과를 보여줍니다. 또한 일부 유효성 검사도 수행하며, 이 재정의로 인해 어떤 형태로든 실패가 발생할 경우 예외를 발생시킵니다. 예시 원격 MySQL 테이블이 다음과 같다고 가정합니다:Query
Query
Response
검증이 완전하지 않으므로, 쿼리가 성공하더라도 재정의로 인해 문제가 발생하지 않는다고 보장할 수는 없습니다.