EXPLAIN: 쿼리 플랜 살펴보기

EXPLAIN: 쿼리 플랜 살펴보기 (EXPLAIN: Inspect Query Plans - explain)

쿼리가 실제로 어떻게 실행되는지, 즉 물리적 실행 계획(physical plan) 을 보고 싶을 때 EXPLAIN을 써요. 쿼리를 실행하지 않고 쿼리 플랜만 출력해줘서, 성능 문제의 원인을 분석하는 데 아주 유용하답니다.

출처: DuckDB 공식 문서 — explain

기본 사용법 (Usage)

EXPLAIN 문은 실행될 쿼리 계획인 물리적 플랜(physical plan) 을 표시해요. 쿼리 앞에 EXPLAIN을 붙이면 활성화되죠.

EXPLAIN SELECT * FROM tbl;

물리적 플랜은 쿼리 결과를 만들기 위해 특정 순서로 실행되는 연산자(operator)들의 트리예요. 효율적인 물리적 플랜을 만들기 위해 쿼리 옵티마이저는 기존 물리적 플랜을 더 나은 플랜으로 변환한답니다.

예제 (Example)

예제를 통해 자세히 볼게요. 먼저 두 테이블을 만들고 데이터를 넣어볼게요.

CREATE TABLE students (name VARCHAR, sid INTEGER);
CREATE TABLE exams (eid INTEGER, subject VARCHAR, sid INTEGER);
INSERT INTO students VALUES ('Mark', 1), ('Joe', 2), ('Matthew', 3);
INSERT INTO exams VALUES (10, 'Physics', 1), (20, 'Chemistry', 2), (30, 'Literature', 3);

EXPLAIN
    SELECT name
    FROM students
    JOIN exams USING (sid)
    WHERE name LIKE 'Ma%';
┌─────────────────────────────┐
│┌───────────────────────────┐│
││       Physical Plan       ││
│└───────────────────────────┘│
└─────────────────────────────┘
┌───────────────────────────┐
│         PROJECTION        │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │
│            name           │
└─────────────┬─────────────┘
┌─────────────┴─────────────┐
│         HASH_JOIN         │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │
│           INNER           │
│         sid = sid         ├──────────────┐
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │              │
│           EC: 1           │              │
└─────────────┬─────────────┘              │
┌─────────────┴─────────────┐┌─────────────┴─────────────┐
│         SEQ_SCAN          ││           FILTER          │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   ││     prefix(name, 'Ma')    │
│           exams           ││   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   ││           EC: 1           │
│            sid            ││                           │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   ││                           │
│           EC: 3           ││                           │
└───────────────────────────┘└─────────────┬─────────────┘
                             ┌─────────────┴─────────────┐
                             │         SEQ_SCAN          │
                             │   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │
                             │          students         │
                             │   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │
                             │            sid            │
                             │            name           │
                             │   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │
                             │ Filters: name>=Ma AND name│
                             │  <Mb AND name IS NOT NULL │
                             │   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │
                             │           EC: 1           │
                             └───────────────────────────┘

여기서 중요한 포인트가 있어요.

  • 쿼리는 실제로 실행되지 않아요. 그래서 각 연산자에 대해 추정 카디널리티(EC, Estimated Cardinality) 만 볼 수 있어요. 이 값은 기본 테이블의 통계를 이용해 각 연산자마다 휴리스틱을 적용해 계산된 거예요.
  • 테이블 스캔 연산자는 카탈로그와 스키마를 포함한 정규화된 테이블 이름을 표시해요. 예: memory.myschema.mytable.

추가 EXPLAIN 설정 (Additional Explain Settings)

EXPLAIN 문은 출력을 제어할 수 있는 추가 설정을 지원해요. 사용 가능한 설정은 다음과 같아요.

기본 설정. 물리적 플랜만 보여줘요.

PRAGMA explain_output = 'physical_only';

최적화된 플랜만 보여줘요.

PRAGMA explain_output = 'optimized_only';

물리적 플랜과 최적화된 플랜 모두 보여줘요.

PRAGMA explain_output = 'all';

더 알아보기 (Learn more)