GET_QUERY_OPERATOR_STATS
GET_QUERY_OPERATOR_STATS
완료된 쿼리 안의 개별 쿼리 연산자들에 대한 통계를 반환해요. 지난 14일 이내에 실행된 완료된 쿼리라면 어떤 쿼리든 이 함수를 실행할 수 있어요.
이 정보를 사용해 쿼리의 구조를 이해하고, 성능 문제를 일으키는 쿼리 연산자(예: 조인 연산자)를 식별할 수 있어요.
예를 들어, 이 정보를 사용해 어떤 연산자가 가장 많은 리소스를 소비하는지 판단할 수 있어요. 또 다른 예로, 이 함수를 사용해 출력 행이 입력 행보다 많은 조인을 식별할 수 있는데, 이는 "폭발(exploding)" 조인(예: 의도하지 않은 카테시안 곱)의 신호일 수 있어요.
이 통계는 Snowsight의 쿼리 프로파일 탭에서도 사용할 수 있어요. GET_QUERY_OPERATOR_STATS() 함수는 같은 정보를 프로그래매틱 인터페이스로 제공해요.
문제가 되는 쿼리 연산자를 찾는 방법에 대한 자세한 내용은 Query Profile로 식별되는 일반적인 쿼리 문제 문서를 참고하세요.
본문
구문
GET_QUERY_OPERATOR_STATS( <query_id> )
인자
query_id
- 쿼리의 ID예요. 다음 중 하나를 사용할 수 있어요: 문자열 리터럴(작은따옴표로 감싼 문자열). 쿼리 ID를 담은 세션 변수. LAST_QUERY_ID 함수 호출의 반환 값.
반환 값
GET_QUERY_OPERATOR_STATS 함수는 테이블 함수예요. 쿼리의 각 쿼리 연산자에 대한 통계를 담은 행을 반환해요. 자세한 내용은 아래의 사용 시 참고 사항과 출력 섹션을 참고하세요.
사용 시 참고 사항
- 이 함수는 완료된 쿼리에 대해서만 통계를 반환해요.
- 쿼리를 실행한 웨어하우스에 대해 OPERATE 또는 MONITOR 권한이 있어야 해요.
- 이 함수는 지정한 쿼리에서 사용된 각 쿼리 연산자에 대한 상세 통계를 제공해요. 가능한 쿼리 연산자 목록은 다음과 같아요. Aggregate: 입력을 그룹화하고 집계 함수를 계산. CartesianJoin: 특수한 유형의 조인. Delete: 테이블에서 레코드를 제거. ExternalFunction: 외부 함수에 의한 처리를 나타냄. ExternalScan: 스테이지 객체에 저장된 데이터에 대한 접근을 나타냄. Filter: 행을 필터링하는 연산을 나타냄. Flatten: VARIANT 레코드를 처리하며, 경우에 따라 지정한 경로에서 평탄화. Generator: TABLE(GENERATOR(…)) 구문으로 레코드를 생성. GroupingSets: GROUPING SETS, ROLLUP, CUBE 같은 구문을 나타냄. Insert: INSERT 또는 COPY 연산을 통해 테이블에 레코드를 추가. InternalObject: 내부 데이터 객체에 대한 접근을 나타냄(예: Information Schema 또는 이전 쿼리 결과). Join: 주어진 조건에서 두 입력을 결합. JoinFilter: 쿼리 계획에서 더 아래 있는 Join의 조건과 일치하지 않을 수 있다고 식별할 수 있는 튜플을 제거하는 특수 필터링 연산. Merge: 테이블에 MERGE 연산 수행. Pivot: 열의 고유 값을 여러 열로 변환하고 필요한 집계를 수행. Result: 쿼리 결과를 반환. Sort: 주어진 표현식으로 입력을 정렬. SortWithLimit: 정렬 후 입력 시퀀스의 일부를 생성. 일반적으로 ORDER BY ... LIMIT ... OFFSET ... 구문의 결과. TableScan: 단일 테이블에 대한 접근을 나타냄. UnionAll: 두 입력을 연결. Unload: 테이블에서 스테이지의 파일로 데이터를 내보내는 COPY 연산을 나타냄. Unpivot: 열을 행으로 변환해 테이블을 회전. Update: 테이블의 레코드를 갱신. ValuesClause: VALUES 절로 제공된 값 목록. WindowFunction: 윈도우 함수를 계산. WithClause: SELECT 문 본문 앞에 오며 하나 이상의 CTE를 정의. WithReference: WITH 절의 인스턴스.
- 정보는 테이블로 반환돼요. 테이블의 각 행은 연산자 하나에 해당해요. 행에는 해당 연산자의 실행 분석(execution breakdown)과 쿼리 통계가 담겨요. 행에는 연산자 속성도 나열될 수 있어요(연산자 타입에 따라 다름). 쿼리 실행 시간을 분석한 통계는 전체 쿼리 실행 시간에 대한 백분율로 표현돼요. 특정 통계에 대한 자세한 내용은 출력(이 문서 주제)을 참고하세요.
- 이 함수는 테이블 함수이므로 FROM 절에서 사용해야 하고 TABLE()로 감싸야 해요. 예를 들어:
SELECT * FROM TABLE(GET_QUERY_OPERATOR_STATS(last_query_id())); - 특정 쿼리(UUID)의 개별 실행마다 이 함수는 결정적이에요. 즉 매번 같은 값을 반환해요. 그러나 같은 쿼리 텍스트의 다른 실행에 대해서는 이 함수가 다른 런타임 통계를 반환할 수 있어요. 통계는 많은 요인에 따라 달라져요. 실행과 따라서 이 함수가 반환하는 통계에 크게 영향을 줄 수 있는 요인은 다음과 같아요: 데이터의 양. 구체화된 뷰의 가용성과, 그 뷰들이 마지막으로 새로고침된 이후 데이터의 변경(있을 경우). 클러스터링의 유무. 이전에 캐시된 데이터의 유무. 가상 웨어하우스의 크기. 사용자 쿼리와 데이터 밖의 요인으로도 값이 영향을 받을 수 있는데, 보통 이런 요인들은 작아요. 그 요인들에는 다음이 포함돼요: 가상 웨어하우스 초기화 시간. 외부 함수의 지연 시간.
출력
이 함수는 다음 열을 반환해요.
| Column name | Data type | Description |
|---|---|---|
| QUERY_ID | VARCHAR | 쿼리 ID. SQL 문에 대한 내부 시스템 생성 식별자. |
| STEP_ID | NUMBER(38, 0) | 쿼리 계획에서 단계의 식별자. |
| OPERATOR_ID | NUMBER(38, 0) | 연산자의 식별자. 쿼리 안에서 고유하며 값은 0부터 시작. |
| PARENT_OPERATORS | ARRAY containing one or more NUMBER(38, 0) | 이 연산자의 부모 연산자 식별자. 쿼리 계획에서 마지막 연산자(보통 Result 연산자)이면 NULL. |
| OPERATOR_TYPE | VARCHAR | 쿼리 연산자의 타입. 예: TableScan 또는 Filter. |
| OPERATOR_STATISTICS | VARIANT containing an OBJECT | 연산자에 대한 통계(예: 연산자의 출력 행 수). |
| EXECUTION_TIME_BREAKDOWN | VARIANT containing an OBJECT | 연산자의 실행 시간 정보. |
| OPERATOR_ATTRIBUTES | VARIANT containing an OBJECT | 연산자에 대한 정보. 이 정보는 연산자 타입에 따라 다름. |
연산자에 대해 특정 열에 정보가 없으면 값은 NULL이에요.
이 열 중 세 개는 OBJECT를 담고 있어요. 각 객체는 키/값 쌍을 담고 있어요. 아래 표들은 이 객체들의 키를 설명해요.
OPERATOR_STATISTICS
OPERATOR_STATISTICS 열의 OBJECT에 있는 필드는 연산자에 대한 추가 정보를 제공해요. 정보에는 다음이 포함될 수 있어요.
| Key | Nested key (if applicable) | Data type | Description |
|---|---|---|---|
| dml | DML(Data Manipulation Language) 쿼리에 대한 통계. | ||
| number_of_rows_inserted | DOUBLE | 테이블(들)에 삽입된 행 수. | |
| number_of_rows_updated | DOUBLE | 테이블에서 갱신된 행 수. | |
| number_of_rows_deleted | DOUBLE | 테이블에서 삭제된 행 수. | |
| number_of_rows_unloaded | DOUBLE | 데이터 내보내기 중 언로드된 행 수. | |
| extension_functions | 확장 함수 호출에 대한 정보. 필드 값이 0이면 해당 필드는 표시되지 않음. | ||
| Java UDF handler load time | DOUBLE | Java UDF 핸들러를 로드하는 데 걸린 시간. | |
| Total Java UDF handler invocations | DOUBLE | Java UDF 핸들러가 호출된 횟수. | |
| Max Java UDF handler execution time | DOUBLE | Java UDF 핸들러가 실행되는 데 걸린 최대 시간. | |
| Avg Java UDF handler execution time | DOUBLE | Java UDF 핸들러를 실행하는 데 걸린 평균 시간. | |
| Java UDTF process() invocations | DOUBLE | Java UDTF process 메서드가 호출된 횟수. | |
| Java UDTF process() execution time | DOUBLE | Java UDTF process를 실행하는 데 걸린 시간. | |
| Avg Java UDTF process() execution time | DOUBLE | Java UDTF process를 실행하는 데 걸린 평균 시간. | |
| Java UDTF's constructor invocations | DOUBLE | Java UDTF 생성자가 호출된 횟수. | |
| Java UDTF's constructor execution time | DOUBLE | Java UDTF 생성자를 실행하는 데 걸린 시간. | |
| Avg Java UDTF's constructor execution time | DOUBLE | Java UDTF 생성자를 실행하는 데 걸린 평균 시간. | |
| Java UDTF endPartition() invocations | DOUBLE | Java UDTF endPartition 메서드가 호출된 횟수. | |
| Java UDTF endPartition() execution time | DOUBLE | Java UDTF endPartition 메서드를 실행하는 데 걸린 시간. | |
| Avg Java UDTF endPartition() execution time | DOUBLE | Java UDTF endPartition 메서드를 실행하는 데 걸린 평균 시간. | |
| Max Java UDF dependency download time | DOUBLE | Java UDF 종속성을 다운로드하는 데 걸린 최대 시간. | |
| Max JVM memory usage | DOUBLE | JVM이 보고한 최대 메모리 사용량. | |
| Java UDF inline code compile time in ms | DOUBLE | Java UDF 인라인 코드의 컴파일 시간. | |
| Total Python UDF handler invocations | DOUBLE | Python UDF 핸들러가 호출된 횟수. | |
| Total Python UDF handler execution time | DOUBLE | Python UDF 핸들러의 총 실행 시간. | |
| Avg Python UDF handler execution time | DOUBLE | Python UDF 핸들러를 실행하는 데 걸린 평균 시간. | |
| Python sandbox max memory usage | DOUBLE | Python 샌드박스 환경의 최대 메모리 사용량. | |
| Avg Python env creation time: Download and install packages | DOUBLE | 패키지 다운로드·설치를 포함한 Python 환경 생성에 걸린 평균 시간. | |
| Conda solver time | DOUBLE | Conda solver로 Python 패키지를 해석하는 데 걸린 시간. | |
| Conda env creation time | DOUBLE | Python 환경을 만드는 데 걸린 시간. | |
| Python UDF initialization time | DOUBLE | Python UDF를 초기화하는 데 걸린 시간. | |
| Number of external file bytes read for UDFs | DOUBLE | UDF를 위해 읽은 외부 파일 바이트 수. | |
| Number of external files accessed for UDFs | DOUBLE | UDF를 위해 접근한 외부 파일 수. | |
| external_functions | 외부 함수 호출에 대한 정보. 필드 값(예: retries_due_to_transient_errors)이 0이면 해당 필드는 표시되지 않음. | ||
| total_invocations | DOUBLE | 외부 함수가 호출된 횟수. 행이 배치되는 배치 수, 일시적 네트워크 문제 시 재시도 횟수 등으로 인해 SQL 문 텍스트의 외부 함수 호출 수와 다를 수 있음. | |
| rows_sent | DOUBLE | 외부 함수로 보낸 행 수. | |
| rows_received | DOUBLE | 외부 함수로부터 받은 행 수. | |
| bytes_sent (x-region) | DOUBLE | 외부 함수로 보낸 바이트 수. 키에 (x-region)이 포함되면 데이터가 지역 간에 전송되었으며 청구에 영향을 줄 수 있음을 뜻함. | |
| bytes_received (x-region) | DOUBLE | 외부 함수로부터 받은 바이트 수. 키에 (x-region)이 포함되면 데이터가 지역 간에 전송되었으며 청구에 영향을 줄 수 있음을 뜻함. | |
| retries_due_to_transient_errors | DOUBLE | 일시적 오류로 인한 재시도 횟수. | |
| average_latency_per_call | DOUBLE | Snowflake가 데이터를 보내고 받은 데이터를 수신한 사이의 호출당 평균 시간(밀리초). | |
| http_4xx_errors | INTEGER | 4xx 상태 코드를 반환한 HTTP 요청의 총 수. | |
| http_5xx_errors | INTEGER | 5xx 상태 코드를 반환한 HTTP 요청의 총 수. | |
| average_latency | DOUBLE | 성공한 HTTP 요청의 평균 지연 시간. | |
| avg_throttle_latency_overhead | DOUBLE | 스로틀링(HTTP 429)으로 인한 지연 때문에 성공한 요청당 평균 오버헤드. | |
| batches_retried_due_to_throttling | DOUBLE | HTTP 429 오류로 재시도된 배치 수. | |
| latency_per_successful_call_(p50) | DOUBLE | 성공한 HTTP 요청의 50번째 백분위수 지연 시간. 성공한 요청의 50%가 이 시간보다 짧게 완료됨. | |
| latency_per_successful_call_(p90) | DOUBLE | 성공한 HTTP 요청의 90번째 백분위수 지연 시간. 성공한 요청의 90%가 이 시간보다 짧게 완료됨. | |
| latency_per_successful_call_(p95) | DOUBLE | 성공한 HTTP 요청의 95번째 백분위수 지연 시간. 성공한 요청의 95%가 이 시간보다 짧게 완료됨. | |
| latency_per_successful_call_(p99) | DOUBLE | 성공한 HTTP 요청의 99번째 백분위수 지연 시간. 성공한 요청의 99%가 이 시간보다 짧게 완료됨. | |
| input_rows | INTEGER | 입력 행 수. 다른 연산자에서 입력 간선이 없는 연산자에는 없을 수 있음. | |
| io | 쿼리 중 수행된 I/O(입출력) 연산에 대한 정보. | ||
| scan_progress | DOUBLE | 지금까지 주어진 테이블에 대해 스캔된 데이터의 백분율. | |
| bytes_scanned | DOUBLE | 지금까지 스캔된 바이트 수. | |
| percentage_scanned_from_cache | DOUBLE | 로컬 디스크 캐시에서 스캔된 데이터의 백분율. | |
| bytes_written | DOUBLE | 기록된 바이트. 예: 테이블에 로드할 때. | |
| bytes_written_to_result | DOUBLE | 결과 객체에 기록된 바이트. 예: SELECT * FROM ...은 선택 항목의 각 필드를 나타내는 표 형식의 결과 집합을 생성. 일반적으로 results 객체는 쿼리 결과로 생성된 모든 것을 나타내고, bytes_written_to_result는 반환된 결과의 크기를 나타냄. |
|
| bytes_read_from_result | DOUBLE | 결과 객체에서 읽은 바이트. | |
| external_bytes_scanned | DOUBLE | 외부 객체(예: 스테이지)에서 읽은 바이트. | |
| network | network_bytes | DOUBLE | 네트워크를 통해 전송된 데이터의 양. |
| output_rows | INTEGER | 출력 행 수. 사용자에게 결과를 반환하는 연산자(보통 RESULT 연산자)에는 없을 수 있음. | |
| pruning | 테이블 프루닝 정보. | ||
| partitions_pruned_by_snowflake_optima | DOUBLE | Snowflake Optima가 프루닝한 파티션 수. | |
| partitions_scanned | DOUBLE | 지금까지 스캔된 파티션 수. | |
| partitions_total | DOUBLE | 주어진 테이블의 총 파티션 수. | |
| spilling | 중간 결과가 메모리에 맞지 않는 연산의 디스크 사용량 정보. | ||
| bytes_spilled_remote_storage | DOUBLE | 원격 디스크로 넘겨진 데이터의 양. | |
| bytes_spilled_local_storage | DOUBLE | 로컬 디스크로 넘겨진 데이터의 양. | |
| search_optimization | 검색 최적화 서비스를 사용하는 쿼리에 대한 정보. | ||
| partitions_pruned_by_search_optimization | DOUBLE | 검색 최적화가 프루닝한 파티션 수. | |
| partitions_pruned_by_search_optimization_and_snowflake_optima | DOUBLE | 검색 최적화와 Snowflake Optima가 프루닝한 파티션 수. |
EXECUTION_TIME_BREAKDOWN
EXECUTION_TIME_BREAKDOWN 열의 OBJECT에 있는 필드는 아래와 같아요.
| Key | Data type | Description |
|---|---|---|
| overall_percentage | DOUBLE | 이 연산자가 사용한 총 쿼리 시간의 백분율. |
| initialization | DOUBLE | 쿼리 처리를 설정하는 데 걸린 시간. |
| processing | DOUBLE | CPU가 데이터를 처리하는 데 걸린 시간. |
| synchronization | DOUBLE | 참여하는 프로세스 간 활동을 동기화하는 데 걸린 시간. |
| local_disk_io | DOUBLE | 로컬 디스크 접근을 기다리는 동안 처리가 차단된 시간. |
| remote_disk_io | DOUBLE | 원격 디스크 접근을 기다리는 동안 처리가 차단된 시간. |
| network_communication | DOUBLE | 네트워크 데이터 전송을 기다리는 동안 처리가 차단된 시간. |
OPERATOR_ATTRIBUTES
각 출력 행은 쿼리의 연산자 하나를 설명해요. 아래 표는 가능한 연산자 타입(예: Filter 연산자)을 보여줘요. 각 연산자 타입에 대해 표는 가능한 속성(예: 행을 필터링하는 데 사용된 표현식)을 보여줘요.
연산자 속성은 VARIANT 타입이고 OBJECT를 담고 있는 OPERATOR_ATTRIBUTES 열에 저장돼요. OBJECT는 키/값 쌍을 담고 있어요. 각 키는 연산자의 속성 하나에 해당해요.
| Operator name | Key | Data type | Description |
|---|---|---|---|
| Aggregate | |||
| functions | ARRAY of VARCHAR | 계산된 함수 목록. | |
| grouping_keys | ARRAY of VARCHAR | 그룹화 표현식. | |
| CartesianJoin | |||
| additional_join_condition | VARCHAR | 비동등 조인 표현식. | |
| equality_join_condition | VARCHAR | 동등 조인 표현식. | |
| join_type | VARCHAR | 조인 타입(INNER). | |
| Delete | table_name | VARCHAR | 갱신된 테이블의 이름. |
| ExternalScan | |||
| stage_name | VARCHAR | 데이터를 읽은 스테이지의 이름. | |
| stage_type | VARCHAR | 스테이지의 타입. | |
| Filter | filter_condition | VARCHAR | 데이터를 필터링하는 데 사용된 표현식. |
| Flatten | input | VARCHAR | 데이터를 평탄화하는 데 사용된 입력 표현식. |
| Generator | |||
| row_count | NUMBER | 입력 매개변수 ROWCOUNT의 값. | |
| time_limit | NUMBER | 입력 매개변수 TIMELIMIT의 값. | |
| GroupingSets | |||
| functions | ARRAY of VARCHAR | 계산된 함수 목록. | |
| key_sets | ARRAY of VARCHAR | 그룹핑 셋 목록. | |
| Insert | |||
| input_expression | VARCHAR | 어떤 표현식이 삽입되는지. | |
| table_names | ARRAY of VARCHAR | 레코드가 추가되는 테이블 이름 목록. | |
| InternalObject | object_name | VARCHAR | 접근된 객체의 이름. |
| Join | |||
| additional_join_condition | VARCHAR | 비동등 조인 표현식. | |
| equality_join_condition | VARCHAR | 동등 조인 표현식. | |
| join_type | VARCHAR | 조인 타입(INNER, OUTER, LEFT JOIN 등). | |
| JoinFilter | join_id | NUMBER | 필터링할 수 있는 튜플을 식별하는 데 사용된 조인의 연산자 ID. |
| Merge | table_name | VARCHAR | 갱신된 테이블의 이름. |
| Pivot | |||
| grouping_keys | ARRAY of VARCHAR | 결과가 집계되는 나머지 열. | |
| pivot_column | ARRAY of VARCHAR | 피벗 값의 결과 열. | |
| Result | expressions | ARRAY of VARCHAR | 생성된 표현식 목록. |
| Sort | sort_keys | ARRAY of VARCHAR | 정렬 순서를 정의하는 표현식. |
| SortWithLimit | |||
| offset | NUMBER | 생성된 튜플을 내보내는 정렬 순서에서의 위치. | |
| rows | NUMBER | 생성된 행 수. | |
| sort_keys | ARRAY of VARCHAR | 정렬 순서를 정의하는 표현식. | |
| TableScan | |||
| columns | ARRAY of VARCHAR | 스캔된 열 목록. | |
| extracted_variant_paths | ARRAY of VARCHAR | variant 열에서 추출된 경로 목록. | |
| table_alias | VARCHAR | 접근 중인 테이블의 별칭. | |
| table_name | VARCHAR | 접근 중인 테이블의 이름. | |
| Unload | location | VARCHAR | 데이터가 저장되는 스테이지. |
| Unpivot | expressions | ARRAY of VARCHAR | unpivot 쿼리의 출력 열. |
| Update | table_name | VARCHAR | 갱신된 테이블의 이름. |
| ValuesClause | |||
| value_count | NUMBER | 생성된 값의 수. | |
| values | VARCHAR | 값 목록. | |
| WindowFunction | functions | ARRAY of VARCHAR | 계산된 함수 목록. |
| WithClause | name | VARCHAR | WITH 절의 별칭. |
연산자가 나열되지 않으면 생성되는 속성이 없으며 값은 {}로 보고돼요.
참고: 다음 연산자는 연산자 속성이 없으므로 OPERATOR_ATTRIBUTES 표에 포함되지 않아요: UnionAll, ExternalFunction.
예시
다음 예시들은 GET_QUERY_OPERATOR_STATS 함수를 호출해요.
단일 쿼리에 대한 데이터 가져오기
이 예시는 두 개의 작은 테이블을 조인하는 SELECT에 대한 통계를 보여줘요.
SELECT 문을 실행합니다.
SELECT x1.i, x2.i
FROM x1 INNER JOIN x2 ON x2.i = x1.i
ORDER BY x1.i, x2.i;
쿼리 ID를 가져옵니다.
SET lqid = (SELECT LAST_QUERY_ID());
GET_QUERY_OPERATOR_STATS()를 호출해 쿼리의 개별 쿼리 연산자에 대한 통계를 가져옵니다.
SELECT * FROM TABLE(GET_QUERY_OPERATOR_STATS($lqid));
+--------------------------------------+---------+-------------+--------------------+---------------+-----------------------------------------+-----------------------------------------------+----------------------------------------------------------------------+
| QUERY_ID | STEP_ID | OPERATOR_ID | PARENT_OPERATORS | OPERATOR_TYPE | OPERATOR_STATISTICS | EXECUTION_TIME_BREAKDOWN | OPERATOR_ATTRIBUTES |
|--------------------------------------+---------+-------------+--------------------+---------------+-----------------------------------------+-----------------------------------------------+----------------------------------------------------------------------|
| 01a8f330-0507-3f5b-0000-43830248e09a | 1 | 0 | NULL | Result | { | { | { |
| | | | | | "input_rows": 64 | "overall_percentage": 0.000000000000000e+00 | "expressions": [ |
| | | | | | } | } | "X1.I", |
| | | | | | | | "X2.I" |
| | | | | | | | ] |
| | | | | | | | } |
| 01a8f330-0507-3f5b-0000-43830248e09a | 1 | 1 | [ 0 ] | Sort | { | { | { |
| | | | | | "input_rows": 64, | "overall_percentage": 0.000000000000000e+00 | "sort_keys": [ |
| | | | | | "output_rows": 64 | } | "X1.I ASC NULLS LAST", |
| | | | | | } | | "X2.I ASC NULLS LAST" |
| | | | | | | | ] |
| | | | | | | | } |
| 01a8f330-0507-3f5b-0000-43830248e09a | 1 | 2 | [ 1 ] | Join | { | { | { |
| | | | | | "input_rows": 128, | "overall_percentage": 0.000000000000000e+00 | "equality_join_condition": "(X2.I = X1.I)", |
| | | | | | "output_rows": 64 | } | "join_type": "INNER" |
| | | | | | } | | } |
| 01a8f330-0507-3f5b-0000-43830248e09a | 1 | 3 | [ 2 ] | TableScan | { | { | { |
| | | | | | "io": { | "overall_percentage": 0.000000000000000e+00 | "columns": [ |
| | | | | | "bytes_scanned": 1024, | } | "I" |
| | | | | | "percentage_scanned_from_cache": 1, | | ], |
| | | | | | "scan_progress": 1 | | "table_name": "MY_DB.MY_SCHEMA.X2" |
| | | | | | }, | | } |
| | | | | | "output_rows": 64, | | |
| | | | | | "pruning": { | | |
| | | | | | "partitions_scanned": 1, | | |
| | | | | | "partitions_total": 1 | | |
| | | | | | } | | |
| | | | | | } | | |
| 01a8f330-0507-3f5b-0000-43830248e09a | 1 | 4 | [ 2 ] | JoinFilter | { | { | { |
| | | | | | "input_rows": 64, | "overall_percentage": 0.000000000000000e+00 | "join_id": "2" |
| | | | | | "output_rows": 64 | } | } |
| | | | | | } | | |
| 01a8f330-0507-3f5b-0000-43830248e09a | 1 | 5 | [ 4 ] | TableScan | { | { | { |
| | | | | | "io": { | "overall_percentage": 0.000000000000000e+00 | "columns": [ |
| | | | | | "bytes_scanned": 1024, | } | "I" |
| | | | | | "percentage_scanned_from_cache": 1, | | ], |
| | | | | | "scan_progress": 1 | | "table_name": "MY_DB.MY_SCHEMA.X1" |
| | | | | | }, | | } |
| | | | | | "output_rows": 64, | | |
| | | | | | "pruning": { | | |
| | | | | | "partitions_scanned": 1, | | |
| | | | | | "partitions_total": 1 | | |
| | | | | | } | | |
| | | | | | } | | |
+--------------------------------------+---------+-------------+--------------------+---------------+-----------------------------------------+-----------------------------------------------+----------------------------------------------------------------------+
"폭발" 조인 연산자 식별하기
다음 예시는 GET_QUERY_OPERATOR_STATS를 사용해 복잡한 쿼리를 조사하는 방법을 보여줘요. 이 예시는 쿼리 안에서 입력된 행보다 훨씬 많은 행을 만드는 연산자를 찾아요.
분석할 쿼리는 다음과 같아요.
SELECT *
FROM t1
JOIN t2 ON t1.a = t2.a
JOIN t3 ON t1.b = t3.b
JOIN t4 ON t1.c = t4.c;
이전 쿼리의 쿼리 ID를 가져옵니다.
SET lid = LAST_QUERY_ID();
다음 쿼리는 쿼리에서 각 조인 연산자에 대한 출력 행 대 입력 행 비율을 보여줘요.
SELECT operator_id,
operator_attributes,
operator_statistics:output_rows / operator_statistics:input_rows AS row_multiple
FROM TABLE(GET_QUERY_OPERATOR_STATS($lid))
WHERE operator_type = 'Join'
ORDER BY step_id, operator_id;
+---------+-------------+--------------------------------------------------------------------------+---------------+
| STEP_ID | OPERATOR_ID | OPERATOR_ATTRIBUTES | ROW_MULTIPLE |
+---------+-------------+--------------------------------------------------------------------------+---------------+
| 1 | 1 | { "equality_join_condition": "(T4.C = T1.C)", "join_type": "INNER" } | 49.969249692 |
| 1 | 3 | { "equality_join_condition": "(T3.B = T1.B)", "join_type": "INNER" } | 116.071428571 |
| 1 | 5 | { "equality_join_condition": "(T2.A = T1.A)", "join_type": "INNER" } | 12.20657277 |
+---------+-------------+--------------------------------------------------------------------------+---------------+
폭발 조인을 식별한 후에는 각 조인 조건을 검토해 조건이 올바른지 확인할 수 있어요.
더 알아보기
- System functions — 시스템 함수 모음
- Table functions — 테이블 함수 모음
- LAST_QUERY_ID — 마지막 쿼리 ID 반환
- GENERATOR — 행 생성