EXPLAIN
EXPLAIN
지정한 SQL 문장의 논리적 실행 계획(logical execution plan)을 반환하는 명령이에요. explain plan은 쿼리를 실행하기 위해 Snowflake가 수행할 작업(예: 테이블 스캔과 조인)을 보여줘요.
출처: 문서
본문
구문 (Syntax)
EXPLAIN [ USING { TABULAR | JSON | TEXT } ] <statement>
파라미터
- statement — explain plan을 원하는 SQL 문장.
- USING output_format — 선택 절로 출력 형식을 지정해요. 가능한 출력 형식:
JSON: JSON 출력은 테이블에 저장하고 쿼리하기 더 쉬워요.TABULAR: 표 형식 출력은 일반적으로 JSON보다 사람이 읽기 쉬워요.TEXT: 포맷된 텍스트 출력은 일반적으로 JSON보다 사람이 읽기 쉬워요.- 기본값은
TABULAR.
출력 (Output)
출력은 다음 정보를 포함해요:
| Column | Description |
|---|---|
| step | 대부분의 쿼리는 단일 단계를 포함하지만 일부는 여러 개의 개별 단계로 실행돼요. 이 열은 작업이 어떤 단계에 속하는지 나타내요. |
| id | 쿼리 계획의 각 작업에 할당된 고유 식별자. |
| parentOperators | 작업의 부모 노드 식별자 배열. 쿼리 프로필에서 부모는 자식 위에 링크로 연결되어 표시돼요. |
| operation | 작업의 이름. 예: Result, Filter, TableScan, Join, CreateTableFromArchiveData. |
| objects | 테이블 스캔 작업이 참조하는 객체의 이름. 예: table, materialized view, secure view, ARCHIVE OF. |
| alias | 참조된 객체의 별칭(쿼리에서 객체에 별칭이 주어졌다면). |
| expressions | 현재 작업과 관련된 표현식 목록(필터, 조인 조건, 프로젝션, 집계 등). |
| partitionsTotal | 참조된 데이터베이스 객체의 총 마이크로 파티션 수. |
| partitionsAssigned | 컴파일 타임 조정(pruning) 후 참조된 객체에서 남은 파티션 수, 즉 쿼리가 스캔할 수 있는 파티션 수. |
| bytesAssigned | partitionsAssigned에 포함된 바이트 수. |
사용 메모 (Usage notes)
- EXPLAIN은 SQL 문장을 컴파일하지만 실행하지 않으므로 실행 중인 웨어하우스가 필요하지 않아요.
- EXPLAIN 계획은 현재 웨어하우스 크기에 따라 달라질 수 있어요. 현재 웨어하우스 외부에서 EXPLAIN을 실행하면 Snowflake는 XSMALL 웨어하우스의 용량을 기준으로 EXPLAIN 계획을 구성해요.
- EXPLAIN은 컴퓨팅 크레딧을 소비하지 않지만, 쿼리 컴파일은 다른 메타데이터 작업처럼 Cloud Service 크레딧을 소비해요.
- 이 명령의 출력을 후처리하려면:
- 출력을 쿼리할 수 있는 테이블로 취급하는
RESULT_SCAN함수를 사용할 수 있어요. - JSON 형식으로 출력을 생성하고 나중에 분석을 위해 JSON 형식 출력을 테이블에 삽입할 수 있어요. JSON 형식으로 출력을 저장하면
SYSTEM$EXPLAIN_JSON_TO_TEXT또는EXPLAIN_JSON함수를 사용하여 JSON을 더 사람이 읽기 쉬운 형식(표 또는 포맷된 텍스트)으로 변환할 수 있어요.
- 출력을 쿼리할 수 있는 테이블로 취급하는
- assignedPartitions와 assignedBytes 값은 쿼리 실행의 상한 추정치예요. 조인 조정(pruning) 같은 런타임 최적화는 쿼리 실행 중 스캔되는 파티션과 바이트 수를 줄일 수 있어요.
- EXPLAIN 계획은 "논리적" explain plan이에요. 수행될 작업과 그 작업들 사이의 논리적 관계를 보여줘요. 계획에서 작업의 실제 실행 순서가 계획이 보여주는 논리적 순서와 반드시 일치하지는 않아요.
- EXPLAIN 문장의 데이터베이스 객체 중 하나라도 INFORMATION_SCHEMA 객체이면 문장은
EXPLAIN command has insufficient privilege on object <objName>오류로 실패해요.
예시 (Examples)
이 예시는 두 개의 작은 테이블에 대한 간단한 쿼리의 EXPLAIN 출력을 보여줘요.
테이블을 만들어요:
CREATE TABLE Z1 (ID INTEGER);
CREATE TABLE Z2 (ID INTEGER);
CREATE TABLE Z3 (ID INTEGER);
쿼리의 EXPLAIN 계획을 표 형식으로 생성해요:
EXPLAIN USING TABULAR SELECT Z1.ID, Z2.ID
FROM Z1, Z2
WHERE Z2.ID = Z1.ID;
+------+------+-----------------+-------------+------------------------------+-------+--------------------------+-----------------+--------------------+---------------+
| step | id | parentOperators | operation | objects | alias | expressions | partitionsTotal | partitionsAssigned | bytesAssigned |
|------+------+-----------------+-------------+------------------------------+-------+--------------------------+-----------------+--------------------+---------------|
| NULL | NULL | NULL | GlobalStats | NULL | NULL | NULL | 2 | 2 | 1024 |
| 1 | 0 | NULL | Result | NULL | NULL | Z1.ID, Z2.ID | NULL | NULL | NULL |
| 1 | 1 | [0] | InnerJoin | NULL | NULL | joinKey: (Z2.ID = Z1.ID) | NULL | NULL | NULL |
| 1 | 2 | [1] | TableScan | TESTDB.TEMPORARY_DOC_TEST.Z2 | NULL | ID | 1 | 1 | 512 |
| 1 | 3 | [1] | JoinFilter | NULL | NULL | joinKey: (Z2.ID = Z1.ID) | NULL | NULL | NULL |
| 1 | 4 | [3] | TableScan | TESTDB.TEMPORARY_DOC_TEST.Z1 | NULL | ID | 1 | 1 | 512 |
+------+------+-----------------+-------------+------------------------------+-------+--------------------------+-----------------+--------------------+---------------+
쿼리의 EXPLAIN 계획을 포맷된 텍스트로 생성해요:
EXPLAIN USING TEXT SELECT Z1.ID, Z2.ID
FROM Z1, Z2
WHERE Z2.ID = Z1.ID;
+------------------------------------------------------------------------------------------------------------------------------------+
| content |
|------------------------------------------------------------------------------------------------------------------------------------|
| GlobalStats: |
| partitionsTotal=2 |
| partitionsAssigned=2 |
| bytesAssigned=1024 |
| Operations: |
| 1:0 ->Result Z1.ID, Z2.ID |
| 1:1 ->InnerJoin joinKey: (Z2.ID = Z1.ID) |
| 1:2 ->TableScan TESTDB.TEMPORARY_DOC_TEST.Z2 ID {partitionsTotal=1, partitionsAssigned=1, bytesAssigned=512} |
| 1:3 ->JoinFilter joinKey: (Z2.ID = Z1.ID) |
| 1:4 ->TableScan TESTDB.TEMPORARY_DOC_TEST.Z1 ID {partitionsTotal=1, partitionsAssigned=1, bytesAssigned=512} |
| |
+------------------------------------------------------------------------------------------------------------------------------------+
쿼리의 EXPLAIN 계획을 JSON으로 생성해요:
EXPLAIN USING JSON SELECT Z1.ID, Z2.ID
FROM Z1, Z2
WHERE Z2.ID = Z1.ID;
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| content |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| {"GlobalStats":{"partitionsTotal":2,"partitionsAssigned":2,"bytesAssigned":1024},"Operations":[[{"id":0,"operation":"Result","expressions":["Z1.ID","Z2.ID"]},{"id":1,"parentOperators":[0],"operation":"InnerJoin","expressions":["joinKey: (Z2.ID = Z1.ID)"]},{"id":2,"parentOperators":[1],"operation":"TableScan","objects":["TESTDB.TEMPORARY_DOC_TEST.Z2"],"expressions":["ID"],"partitionsAssigned":1,"partitionsTotal":1,"bytesAssigned":512},{"id":3,"parentOperators":[1],"operation":"JoinFilter","expressions":["joinKey: (Z2.ID = Z1.ID)"]},{"id":4,"parentOperators":[3],"operation":"TableScan","objects":["TESTDB.TEMPORARY_DOC_TEST.Z1"],"expressions":["ID"],"partitionsAssigned":1,"partitionsTotal":1,"bytesAssigned":512}]]} |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+