EXPLAIN ANALYZE

EXPLAIN ANALYZE

쿼리를 실제로 실행하면서 각 연산의 비용(cost)과 함께 분산 실행 계획을 보여주는 명령어예요. 계획만 보는 EXPLAIN과 달리 실제로 실행하고 측정해요.

출처: 문서

본문

Synopsis

EXPLAIN ANALYZE [VERBOSE] statement

Description

문장을 실행하고 그 문장의 분산 실행 계획을 각 연산의 비용과 함께 보여줘요.

VERBOSE 옵션은 더 상세한 정보와 저수준 통계를 제공해요. 이를 이해하려면 Trino 내부 동작과 구현 세부 사항에 대한 지식이 필요할 수 있어요.

Note

통계는 특히 빠르게 완료되는 쿼리의 경우 완전히 정확하지 않을 수 있어요.

Examples

아래 예시에서 각 스테이지에서 보낸 CPU 시간과 스테이지 안 각 계획 노드의 상대적 비용을 볼 수 있어요. 계획 노드의 상대적 비용은 wall time 기준이며, CPU 시간과 상관관계가 있을 수도 있고 없을 수도 있어요. 각 계획 노드에 대해 추가 통계(예: 노드 인스턴스당 평균 입력)를 볼 수 있어요. 이런 통계는 쿼리의 데이터 이상(예: 어느 한쪽으로 치우친 skewness)을 감지하려 할 때 유용해요.

EXPLAIN ANALYZE SELECT count(*), clerk FROM orders
WHERE orderdate > date '1995-01-01' GROUP BY clerk;
                                          Query Plan
-----------------------------------------------------------------------------------------------
Trino version: version
Queued: 374.17us, Analysis: 190.96ms, Planning: 179.03ms, Execution: 3.06s
Fragment 1 [HASH]
    CPU: 22.58ms, Scheduled: 96.72ms, Blocked 46.21s (Input: 23.06s, Output: 0.00ns), Input: 1000 rows (37.11kB); per task: avg.: 1000.00 std.dev.: 0.00, Output: 1000 rows (28.32kB)
    Output layout: [clerk, count]
    Output partitioning: SINGLE []
    Project[]
    │   Layout: [clerk:varchar(15), count:bigint]
    │   Estimates: {rows: ? (?), cpu: ?, memory: 0B, network: 0B}
    │   CPU: 8.00ms (3.51%), Scheduled: 63.00ms (15.11%), Blocked: 0.00ns (0.00%), Output: 1000 rows (28.32kB)
    │   Input avg.: 15.63 rows, Input std.dev.: 24.36%
    └─ Aggregate[type = FINAL, keys = [clerk], hash = [$hashvalue]]
       │   Layout: [clerk:varchar(15), $hashvalue:bigint, count:bigint]
       │   Estimates: {rows: ? (?), cpu: ?, memory: ?, network: 0B}
       │   CPU: 8.00ms (3.51%), Scheduled: 22.00ms (5.28%), Blocked: 0.00ns (0.00%), Output: 1000 rows (37.11kB)
       │   Input avg.: 15.63 rows, Input std.dev.: 24.36%
       │   count := count("count_0")
       └─ LocalExchange[partitioning = HASH, hashColumn = [$hashvalue], arguments = ["clerk"]]
          │   Layout: [clerk:varchar(15), count_0:bigint, $hashvalue:bigint]
          │   Estimates: {rows: ? (?), cpu: ?, memory: 0B, network: 0B}
          │   CPU: 2.00ms (0.88%), Scheduled: 4.00ms (0.96%), Blocked: 23.15s (50.10%), Output: 1000 rows (37.11kB)
          │   Input avg.: 15.63 rows, Input std.dev.: 793.73%
          └─ RemoteSource[sourceFragmentIds = [2]]
                 Layout: [clerk:varchar(15), count_0:bigint, $hashvalue_1:bigint]
                 CPU: 0.00ns (0.00%), Scheduled: 0.00ns (0.00%), Blocked: 23.06s (49.90%), Output: 1000 rows (37.11kB)
                 Input avg.: 15.63 rows, Input std.dev.: 793.73%

Fragment 2 [SOURCE]
    CPU: 210.60ms, Scheduled: 327.92ms, Blocked 0.00ns (Input: 0.00ns, Output: 0.00ns), Input: 1500000 rows (18.17MB); per task: avg.: 1500000.00 std.dev.: 0.00, Output: 1000 rows (37.11kB)
    Output layout: [clerk, count_0, $hashvalue_2]
    Output partitioning: HASH [clerk][$hashvalue_2]
    Aggregate[type = PARTIAL, keys = [clerk], hash = [$hashvalue_2]]
    │   Layout: [clerk:varchar(15), $hashvalue_2:bigint, count_0:bigint]
    │   CPU: 30.00ms (13.16%), Scheduled: 30.00ms (7.19%), Blocked: 0.00ns (0.00%), Output: 1000 rows (37.11kB)
    │   Input avg.: 818058.00 rows, Input std.dev.: 0.00%
    │   count_0 := count(*)
    └─ ScanFilterProject[table = hive:sf1:orders, filterPredicate = ("orderdate" > DATE '1995-01-01')]
           Layout: [clerk:varchar(15), $hashvalue_2:bigint]
           Estimates: {rows: 1500000 (41.48MB), cpu: 35.76M, memory: 0B, network: 0B}/{rows: 816424 (22.58MB), cpu: 35.76M, memory: 0B, network: 0B}/{rows: 816424 (22.58MB), cpu: 22.58M, memory: 0B, network: 0B}
           CPU: 180.00ms (78.95%), Scheduled: 298.00ms (71.46%), Blocked: 0.00ns (0.00%), Output: 818058 rows (12.98MB)
           Input avg.: 1500000.00 rows, Input std.dev.: 0.00%
           $hashvalue_2 := combine_hash(bigint '0', COALESCE("$operator$hash_code"("clerk"), 0))
           clerk := clerk:varchar(15):REGULAR
           orderdate := orderdate:date:REGULAR
           Input: 1500000 rows (18.17MB), Filtered: 45.46%, Physical Input: 4.51MB

VERBOSE 옵션을 사용하면 일부 연산자가 추가 정보를 보고해요. 예를 들어 윈도우 함수 연산자는 다음과 같은 출력을 보여줘요:

EXPLAIN ANALYZE VERBOSE SELECT count(clerk) OVER() FROM orders
WHERE orderdate > date '1995-01-01';
                                          Query Plan
-----------------------------------------------------------------------------------------------
  ...
         ─ Window[]
           │   Layout: [clerk:varchar(15), count:bigint]
           │   CPU: 157.00ms (53.40%), Scheduled: 158.00ms (37.71%), Blocked: 0.00ns (0.00%), Output: 818058 rows (22.62MB)
           │   metrics:
           │     'CPU time distribution (s)' = {count=1.00, p01=0.16, p05=0.16, p10=0.16, p25=0.16, p50=0.16, p75=0.16, p90=0.16, p95=0.16, p99=0.16, min=0.16, max=0.16}
           │     'Input rows distribution' = {count=1.00, p01=818058.00, p05=818058.00, p10=818058.00, p25=818058.00, p50=818058.00, p75=818058.00, p90=818058.00, p95=818058.00, p99=818058.00, min=818058.00, max=818058.00}
           │     'Scheduled time distribution (s)' = {count=1.00, p01=0.16, p05=0.16, p10=0.16, p25=0.16, p50=0.16, p75=0.16, p90=0.16, p95=0.16, p99=0.16, min=0.16, max=0.16}
           │   Input avg.: 818058.00 rows, Input std.dev.: 0.00%
           │   Active Drivers: [ 1 / 1 ]
           │   Index size: std.dev.: 0.00 bytes, 0.00 rows
           │   Index count per driver: std.dev.: 0.00
           │   Rows per driver: std.dev.: 0.00
           │   Size of partition: std.dev.: 0.00
           │   count := count("clerk") RANGE UNBOUNDED_PRECEDING CURRENT_ROW
 ...

See also

EXPLAIN 명령과 함께 사용해요.

더 알아보기 (Learn more)

실행 없이 계획만 보는 EXPLAIN과 함께 사용하면 계획 단계와 실행 단계를 모두 파악할 수 있어요.