---
title: "MySQL Histogram: 비균등 분포 컬럼에서 실행 계획을 보정하는 방법"
description: "MySQL Histogram이 비인덱스 컬럼의 데이터 분포를 어떻게 모델링하고, 비균등 분포 환경에서 실행 계획 추정을 어떻게 개선하는지 운영 관점에서 정리한다."
tags: [ MySQL, 성능최적화, 인덱스, 운영, DBA ]
image: "mysql-report-bg.png"
published: "2026-07-01"
updated: "2026-07-01"
author: "MySQL 기술 노트"
source_url: ""
---

## 1. 왜 Histogram을 DBA가 알아야 하는가

MySQL 실행 계획 문제를 다루다 보면 “인덱스는 있는데도 왜 이 쿼리가 갑자기 느려졌는가”, 또는 “같은 SQL인데 특정 값에서만 유난히 다른 계획이 나온다” 같은 상황을 자주 만난다. 이런 문제는 단순히 인덱스 유무만으로 설명되지 않는다. 실제 원인은 **데이터 분포가 한쪽으로 치우쳐 있는데 옵티마이저가 이를 충분히 알지 못해 selectivity를 잘못 추정했기 때문**인 경우가 많다.

특히 다음과 같은 컬럼은 문제가 되기 쉽다.

- 고객 등급처럼 소수의 값이 전체 row 대부분을 차지하는 컬럼
- 국가, 리전, 상태값처럼 분포가 극단적으로 비대칭인 컬럼
- 인덱스를 두기에는 애매하지만 필터 조건으로 자주 등장하는 컬럼
- 조인 순서 결정에는 중요하지만 cardinality만으로는 실제 분포를 설명하기 어려운 컬럼

이때 Histogram은 인덱스를 새로 만들지 않고도, **옵티마이저가 값 분포를 더 현실에 가깝게 이해하도록 돕는 보조 통계 정보**다. 중요한 점은 Histogram이 쿼리를 직접 빠르게 실행하는 기능이 아니라는 사실이다. Histogram은 버퍼 풀처럼 row를 캐시하지도 않고, 인덱스처럼 탐색 경로를 제공하지도 않는다. 대신 실행 전 단계에서 비용 추정의 입력을 더 정확하게 만들어, 결과적으로 더 나은 계획을 선택하게 만든다.

운영 관점에서 이것은 매우 중요하다. 잘못된 row estimate는 단일 테이블 access path뿐 아니라 조인 순서, join buffer 사용 여부, range와 scan의 비용 비교, 임시 테이블 발생 여부까지 연쇄적으로 왜곡할 수 있기 때문이다.

## 2. Histogram의 핵심 개념

### 2.1 Histogram은 무엇을 저장하는가

Histogram은 특정 컬럼 값의 분포를 bucket 단위로 요약한 통계 정보다. MySQL 옵티마이저는 이를 사용해 “`col = 'X'` 조건을 걸면 전체 row 중 얼마나 남을 가능성이 큰가”를 더 정확히 추정한다.

단순 cardinality는 “서로 다른 값이 몇 종류인가” 정도만 알려 준다. 하지만 운영 환경에서 중요한 것은 값 종류 수 자체보다 **각 값이 얼마나 불균등하게 퍼져 있는가**다.

예를 들어 다음 두 컬럼은 cardinality가 모두 4일 수 있다.

- 컬럼 A: `KR`, `US`, `JP`, `DE`가 각각 25%씩 분포
- 컬럼 B: `KR` 92%, `US` 5%, `JP` 2%, `DE` 1%

cardinality만 보면 두 컬럼은 비슷해 보이지만, 실제 실행 계획 영향은 전혀 다르다. 컬럼 B에서 `country = 'DE'` 조건은 매우 selective하지만 `country = 'KR'` 조건은 사실상 full scan과 비슷한 비용 구조를 가질 수 있다. Histogram은 이런 차이를 옵티마이저에게 전달하는 수단이다.

### 2.2 Histogram이 특히 유효한 경우

Histogram은 모든 컬럼에 무조건 필요한 기능이 아니다. 보통 다음 조건이 겹칠 때 효과가 크다.

1. 컬럼이 자주 필터 조건에 등장한다.
2. 값 분포가 비균등하다.
3. 별도 인덱스를 두기에는 비용 대비 이점이 불분명하다.
4. 옵티마이저가 그 컬럼의 selectivity를 자주 잘못 추정한다.

즉, Histogram은 “인덱스를 대신하는 만능 도구”가 아니라, **분포 오해를 줄여 계획 추정 오류를 줄이는 보정 장치**라고 보는 편이 정확하다.

### 2.3 Histogram이 해결하지 못하는 것

Histogram이 있다고 해서 다음 문제가 자동으로 해결되지는 않는다.

- 인덱스가 필요한 range access 문제
- 정렬 회피를 위한 index order 문제
- covering index 부재로 인한 random I/O 문제
- 함수 적용, 암묵적 형변환, 비SARGable 조건식 문제
- stale statistics나 잘못된 조인 조건 자체의 구조적 문제

실무적으로는 “이 컬럼에 Histogram을 만들면 빨라지겠지”가 아니라, **현재 병목이 access path 부족인지, selectivity 오판인지**를 먼저 분리해야 한다.

## 3. 옵티마이저가 Histogram을 사용하는 흐름

옵티마이저는 단순히 SQL 문장만 보고 계획을 고르지 않는다. 메타데이터, 인덱스 통계, row 추정, predicate selectivity 추정, 비용 모델을 함께 사용한다. Histogram은 이 중 predicate selectivity 추정 품질을 올리는 쪽에 관여한다.

```mermaid
flowchart LR
    A[WHERE 조건] --> B[옵티마이저]
    C[인덱스 cardinality] --> B
    D[테이블 row 수 추정] --> B
    E[Histogram 분포 정보] --> B
    B --> F[조건별 row estimate 계산]
    F --> G[access path 비교]
    F --> H[조인 순서 비교]
    G --> I[최종 실행 계획]
    H --> I
```

이 구조에서 핵심은 다음과 같다.

- cardinality는 대략적 다양성 정보를 준다.
- Histogram은 값별 분포의 불균형을 더 세밀하게 반영한다.
- 옵티마이저는 이 정보를 합쳐 조건별 남는 row 수를 추정한다.
- 이 추정이 좋아질수록 조인 순서와 access path 판단도 안정된다.

즉, Histogram은 실행 엔진이 아니라 **계획 선택 단계의 정확도를 높이는 통계 계층**이다.

## 4. 비균등 분포에서 왜 문제가 커지는가

데이터가 균등하게 분포하면 평균 기반 추정이 크게 틀리지 않을 수 있다. 그러나 실제 서비스 데이터는 대개 균등하지 않다.

- 최근 주문이 특정 시간대에 몰린다.
- 특정 tenant가 전체 데이터 대부분을 차지한다.
- `ACTIVE` 상태가 98%이고 나머지 상태는 극소수다.
- 국가/리전별 트래픽이 소수 지역에 편중된다.

이 상황에서 옵티마이저가 단순 평균만 믿으면 다음과 같은 오류가 생긴다.

1. 희소 값에 대해서는 너무 많은 row가 나올 것으로 과대추정한다.
2. 흔한 값에 대해서는 너무 적은 row가 나올 것으로 과소추정한다.
3. 그 결과 잘못된 조인 순서를 고르거나, 인덱스 사용 비용을 왜곡해서 비교한다.
4. 특정 파라미터 값에서만 급격히 느려지는 plan instability가 나타난다.

이런 현상은 prepared statement, 배치 SQL, 대시보드 쿼리, 다중 tenant 환경에서 특히 자주 보인다. 애플리케이션 관점에서는 “어떤 고객만 유난히 느리다”로 보이지만, DBA 관점에서는 **데이터 분포 편향을 통계가 제대로 반영하지 못한 결과**일 수 있다.

## 5. Histogram 유형과 운영 해석

MySQL은 내부적으로 bucket 기반의 분포 정보를 유지한다. 운영자가 모든 세부 구현을 외울 필요는 없지만, 다음 정도는 이해해 두는 것이 좋다.

### 5.1 bucket 수는 정밀도와 비용의 절충이다

`ANALYZE TABLE ... UPDATE HISTOGRAM ... WITH N BUCKETS`에서 bucket 수를 크게 잡으면 분포를 더 세밀하게 표현할 수 있지만, 통계 생성과 관리 비용도 늘어난다. 반대로 bucket 수가 너무 작으면 극단적 skew를 충분히 표현하지 못할 수 있다.

실무에서는 무조건 큰 값을 쓰기보다 다음 기준이 유효하다.

- 값 종류가 많지 않은 컬럼이면 과도한 bucket 수는 의미가 작다.
- 분포가 매우 치우친 컬럼이면 너무 적은 bucket은 왜곡을 남긴다.
- 대량 컬럼 전체에 기계적으로 적용하기보다 문제 컬럼 중심으로 선택한다.

### 5.2 Histogram은 인덱스 통계와 경쟁하는 것이 아니라 보완한다

인덱스가 있는 컬럼이라고 해서 Histogram이 항상 무의미한 것은 아니다. 다만 Histogram의 주효과는 대개 **비인덱스 컬럼 또는 인덱스만으로 분포 왜곡을 설명하기 어려운 조건**에서 더 크게 나타난다.

예를 들어 복합 인덱스의 선행 컬럼 cardinality는 알 수 있어도, 특정 비인덱스 필터의 실제 분포는 별도로 설명되지 않을 수 있다. 이때 Histogram은 조인 순서와 filtering factor 계산 보정에 도움을 줄 수 있다.

### 5.3 stale histogram도 문제다

Histogram 역시 생성 이후 영원히 정확한 것이 아니다. 데이터 분포가 변하면 다시 갱신해야 한다. 예를 들어 특정 국가 트래픽이 갑자기 폭증했거나, 신규 서비스 론칭으로 상태값 분포가 바뀌었다면 과거 Histogram은 더 이상 현실을 설명하지 못할 수 있다.

따라서 운영에서는 다음 질문이 중요하다.

- 이 컬럼 분포는 최근 크게 변했는가?
- 계획 변동이 Histogram 도입 전후와 어떤 차이를 보이는가?
- `ANALYZE TABLE` 시점과 배포/이벤트 시점이 맞물려 있는가?

## 6. 예제 1: Histogram 관련 기본 상태 확인

먼저 대상 인스턴스가 Histogram 관련 변수를 어떻게 노출하는지 확인한다. 이는 기능 사용 가능성 자체보다, **이 인스턴스에서 Histogram 생성 작업이 어떤 메모리 한도와 버전 위에서 수행되는지**를 이해하는 출발점이다.

```sql
SELECT VERSION() AS mysql_version;

SHOW VARIABLES LIKE 'histogram_generation_max_mem_size';
```

실행 결과(MySQL 8.0.x):

```text
mysql> SELECT VERSION() AS mysql_version;

+---------------+
| mysql_version |
+---------------+
| 8.0.46        |
+---------------+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES LIKE 'histogram_generation_max_mem_size';

+-----------------------------------+----------+
| Variable_name                     | Value    |
+-----------------------------------+----------+
| histogram_generation_max_mem_size | 20000000 |
+-----------------------------------+----------+
1 row in set (0.00 sec)
```

이 확인은 단순 조회지만 운영적으로 의미가 있다. MySQL minor version, Aurora MySQL 호환 버전, 빌드 차이에 따라 통계 관련 동작과 노출 방식이 조금씩 다를 수 있기 때문이다. 특히 Aurora MySQL에서는 엔진 호환 버전은 MySQL 8.0 계열이어도, 운영자가 체감하는 통계 재수집 시점과 장애 대응 절차는 파라미터 그룹, failover, 읽기 노드 활용 방식에 따라 달라질 수 있으므로 테스트 환경에서 먼저 확인하는 편이 안전하다.

## 7. 예제 2: 비균등 분포 컬럼에서 Histogram 생성 전후 비교

아래 예제는 `region_code` 컬럼의 값 분포가 의도적으로 한쪽에 치우친 테이블을 만들고, Histogram 생성 전후의 `EXPLAIN FORMAT=TREE`를 비교하는 흐름이다. 핵심은 액세스 경로가 반드시 바뀌는지보다, **옵티마이저의 row estimate가 분포 현실에 더 가까워지는지**를 보는 데 있다.

```sql
DROP TABLE IF EXISTS histogram_demo;

CREATE TABLE histogram_demo (
  id INT PRIMARY KEY,
  region_code CHAR(2) NOT NULL,
  created_at DATETIME NOT NULL,
  payload VARCHAR(40) NOT NULL,
  KEY idx_created_at (created_at)
);

INSERT INTO histogram_demo (id, region_code, created_at, payload) VALUES
  (1,  'KR', '2026-07-01 09:00:00', 'evt-001'),
  (2,  'KR', '2026-07-01 09:01:00', 'evt-002'),
  (3,  'KR', '2026-07-01 09:02:00', 'evt-003'),
  (4,  'KR', '2026-07-01 09:03:00', 'evt-004'),
  (5,  'KR', '2026-07-01 09:04:00', 'evt-005'),
  (6,  'KR', '2026-07-01 09:05:00', 'evt-006'),
  (7,  'KR', '2026-07-01 09:06:00', 'evt-007'),
  (8,  'KR', '2026-07-01 09:07:00', 'evt-008'),
  (9,  'KR', '2026-07-01 09:08:00', 'evt-009'),
  (10, 'KR', '2026-07-01 09:09:00', 'evt-010'),
  (11, 'KR', '2026-07-01 09:10:00', 'evt-011'),
  (12, 'KR', '2026-07-01 09:11:00', 'evt-012'),
  (13, 'KR', '2026-07-01 09:12:00', 'evt-013'),
  (14, 'KR', '2026-07-01 09:13:00', 'evt-014'),
  (15, 'KR', '2026-07-01 09:14:00', 'evt-015'),
  (16, 'US', '2026-07-01 09:15:00', 'evt-016'),
  (17, 'US', '2026-07-01 09:16:00', 'evt-017'),
  (18, 'JP', '2026-07-01 09:17:00', 'evt-018'),
  (19, 'DE', '2026-07-01 09:18:00', 'evt-019'),
  (20, 'DE', '2026-07-01 09:19:00', 'evt-020');

EXPLAIN FORMAT=TREE
SELECT *
FROM histogram_demo
WHERE region_code = 'KR';

ANALYZE TABLE histogram_demo UPDATE HISTOGRAM ON region_code WITH 8 BUCKETS;

SELECT COLUMN_NAME,
       JSON_UNQUOTE(JSON_EXTRACT(HISTOGRAM, '$."histogram-type"')) AS histogram_type,
       JSON_EXTRACT(HISTOGRAM, '$."number-of-buckets-specified"') AS buckets
FROM information_schema.COLUMN_STATISTICS
WHERE SCHEMA_NAME = DATABASE()
  AND TABLE_NAME = 'histogram_demo'
  AND COLUMN_NAME = 'region_code';

EXPLAIN FORMAT=TREE
SELECT *
FROM histogram_demo
WHERE region_code = 'KR';

ANALYZE TABLE histogram_demo DROP HISTOGRAM ON region_code;
DROP TABLE IF EXISTS histogram_demo;
```

실행 결과(MySQL 8.0.x):

```text
mysql> DROP TABLE IF EXISTS histogram_demo;

Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE histogram_demo (
    ->   id INT PRIMARY KEY,
    ->   region_code CHAR(2) NOT NULL,
    ->   created_at DATETIME NOT NULL,
    ->   payload VARCHAR(40) NOT NULL,
    ->   KEY idx_created_at (created_at)
    -> );

Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO histogram_demo (id, region_code, created_at, payload) VALUES
    ->   (1,  'KR', '2026-07-01 09:00:00', 'evt-001'),
    ->   ...
    ->   (20, 'DE', '2026-07-01 09:19:00', 'evt-020');

Query OK, 20 rows affected (0.00 sec)
Records: 20  Duplicates: 0  Warnings: 0

mysql> EXPLAIN FORMAT=TREE
    -> SELECT *
    -> FROM histogram_demo
    -> WHERE region_code = 'KR';

+------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                      |
+------------------------------------------------------------------------------------------------------------------------------+
| -> Filter: (histogram_demo.region_code = 'KR')  (cost=2.35 rows=2.1)
    -> Table scan on histogram_demo  (cost=2.35 rows=21)
 |
+------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> ANALYZE TABLE histogram_demo UPDATE HISTOGRAM ON region_code WITH 8 BUCKETS;

+--------------------------------+-----------+----------+--------------------------------------------------------+
| Table                          | Op        | Msg_type | Msg_text                                               |
+--------------------------------+-----------+----------+--------------------------------------------------------+
| mysql_tech_note.histogram_demo | histogram | status   | Histogram statistics created for column 'region_code'. |
+--------------------------------+-----------+----------+--------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT COLUMN_NAME,
    ->        JSON_UNQUOTE(JSON_EXTRACT(HISTOGRAM, '$."histogram-type"')) AS histogram_type,
    ->        JSON_EXTRACT(HISTOGRAM, '$."number-of-buckets-specified"') AS buckets
    -> FROM information_schema.COLUMN_STATISTICS
    -> WHERE SCHEMA_NAME = DATABASE()
    ->   AND TABLE_NAME = 'histogram_demo'
    ->   AND COLUMN_NAME = 'region_code';

+-------------+----------------+---------+
| COLUMN_NAME | histogram_type | buckets |
+-------------+----------------+---------+
| region_code | singleton      | 8       |
+-------------+----------------+---------+
1 row in set (0.00 sec)

mysql> EXPLAIN FORMAT=TREE
    -> SELECT *
    -> FROM histogram_demo
    -> WHERE region_code = 'KR';

+------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                      |
+------------------------------------------------------------------------------------------------------------------------------+
| -> Filter: (histogram_demo.region_code = 'KR')  (cost=1.45 rows=9)
    -> Table scan on histogram_demo  (cost=1.45 rows=12)
 |
+------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> ANALYZE TABLE histogram_demo DROP HISTOGRAM ON region_code;

+--------------------------------+-----------+----------+--------------------------------------------------------+
| Table                          | Op        | Msg_type | Msg_text                                               |
+--------------------------------+-----------+----------+--------------------------------------------------------+
| mysql_tech_note.histogram_demo | histogram | status   | Histogram statistics removed for column 'region_code'. |
+--------------------------------+-----------+----------+--------------------------------------------------------+
1 row in set (0.00 sec)

mysql> DROP TABLE IF EXISTS histogram_demo;

Query OK, 0 rows affected (0.00 sec)
```

이 예제는 다음 순서로 읽는 것이 좋다.

1. Histogram 생성 전 `EXPLAIN`에서 `region_code = 'KR'`의 row estimate를 본다.
2. Histogram 생성 후 `information_schema.COLUMN_STATISTICS`에서 실제 Histogram 메타데이터가 등록되었는지 확인한다.
3. 같은 조건을 다시 `EXPLAIN`해 estimate 변화가 있는지 본다.
4. 이 작은 예제에서는 full scan이 유지되지만, `KR`처럼 비중이 큰 값에 대한 row estimate가 초기의 거의 균등 가정보다 실제 분포 쪽으로 이동하는지를 확인하는 것이 핵심이다.

만약 액세스 경로가 그대로여도 실망할 필요는 없다. Histogram의 1차 목표는 “항상 plan shape를 바꾸는 것”이 아니라, **분포 오판을 줄여 후속 계획 선택을 덜 왜곡시키는 것**이기 때문이다.

## 8. Histogram을 운영에 적용할 때의 판단 기준

Histogram은 문제를 정확히 겨냥했을 때 유용하지만, 무차별 적용하면 관리 포인트만 늘어난다. 다음 질문으로 적용 대상을 좁히는 편이 좋다.

### 8.1 이런 경우 도입을 우선 검토한다

- 특정 값에서만 실행 계획이 유난히 흔들린다.
- `EXPLAIN` row estimate가 실제 row 수와 반복적으로 크게 어긋난다.
- 비인덱스 필터 컬럼이 조인 순서 결정에 큰 영향을 준다.
- 인덱스를 추가하기엔 쓰기 비용, 저장 공간, 유지보수 부담이 더 크다.
- skewed distribution이 명확히 존재한다.

### 8.2 이런 경우는 먼저 다른 원인을 본다

- 함수 적용, 계산식, 타입 변환 때문에 조건이 비SARGable하다.
- 필요한 복합 인덱스 자체가 없다.
- 통계가 아니라 SQL 구조가 비효율적이다.
- stale index statistics, stale table statistics가 더 본질적 문제다.
- 실제 병목이 락 대기, I/O 포화, 네트워크 지연이다.

### 8.3 Aurora MySQL에서의 해석

Aurora MySQL에서도 옵티마이저와 통계 품질은 여전히 중요하다. 다만 운영 절차는 Community MySQL 단일 인스턴스와 약간 다를 수 있다.

- writer/reader 역할과 failover 시점에 통계 점검 절차를 runbook에 포함하는 편이 좋다.
- 파라미터 그룹 변경과 배포 창구를 고려해 `ANALYZE TABLE` 실행 시점을 계획한다.
- 읽기 전용 reader에서 관찰되는 쿼리 패턴과 writer의 데이터 변화 속도가 다를 수 있으므로, 분포 변화 시점과 계획 변화 시점을 함께 본다.

즉, Aurora에서도 Histogram 자체의 개념은 같지만, **언제 만들고 언제 갱신하며 어떤 장애 대응 절차에 엮을 것인가**가 더 중요하다.

## 9. 흔한 오해와 주의점

### 9.1 Histogram이 인덱스를 대체한다는 오해

대체하지 못한다. Histogram은 탐색 경로를 제공하지 않는다. 인덱스가 필요한 문제를 Histogram으로 해결하려 하면 대개 기대한 효과가 나오지 않는다.

### 9.2 bucket 수를 크게 하면 무조건 좋다는 오해

bucket 수를 과도하게 늘린다고 항상 좋은 것은 아니다. 분포를 더 잘 표현할 수는 있지만, 운영 복잡도와 갱신 비용을 함께 고려해야 한다. 문제 컬럼에 제한적으로 적용하는 편이 낫다.

### 9.3 Histogram이 있으면 plan instability가 완전히 사라진다는 오해

Histogram은 row estimate 오류를 줄일 뿐이다. 데이터 증가, 인덱스 추가, 버전 업그레이드, 파라미터 변화, SQL 구조 변경까지 모두 없애 주는 것은 아니다. 따라서 Histogram 도입 전후에도 `EXPLAIN`, 실행 시간, 실제 row 수를 함께 비교해야 한다.

### 9.4 오래된 Histogram을 방치하는 문제

분포가 바뀌었는데 재생성하지 않으면, 오래된 Histogram은 오히려 잘못된 확신을 옵티마이저에 줄 수 있다. 대규모 이벤트, tenant 편중 변화, 아카이빙 작업 이후에는 재점검이 필요하다.

## 10. 실무 체크리스트

- [ ] 이 쿼리의 핵심 문제를 access path 부족과 selectivity 오판 중 어디로 볼지 먼저 구분했다.
- [ ] 비균등 분포가 의심되는 컬럼을 실제 데이터 분포로 확인했다.
- [ ] `EXPLAIN`의 row estimate와 실제 row 수 차이를 비교했다.
- [ ] 인덱스 추가가 더 적절한 문제인지 먼저 검토했다.
- [ ] Histogram 생성 전후로 실행 계획과 응답 시간을 비교했다.
- [ ] `information_schema.COLUMN_STATISTICS`에서 Histogram 등록 여부를 확인했다.
- [ ] 데이터 분포가 크게 변하는 이벤트 이후 재생성 시점을 운영 runbook에 반영했다.
- [ ] Aurora MySQL 환경이라면 배포/파라미터 그룹/failover 절차와 함께 적용 계획을 세웠다.

## 11. 결론

Histogram은 MySQL에서 상대적으로 과소평가되기 쉬운 기능이지만, 비균등 분포 컬럼 때문에 selectivity 추정이 흔들리는 환경에서는 매우 실용적인 도구다. 핵심은 Histogram을 “인덱스 대체재”로 보는 것이 아니라, **옵티마이저가 데이터 현실을 더 정확히 이해하게 만드는 분포 통계**로 이해하는 데 있다.

실무에서는 단순히 Histogram을 켜는 것보다, 어떤 컬럼이 skewed distribution을 가지고 있고 그 왜곡이 실제 실행 계획에 어떤 영향을 주는지를 먼저 읽어내는 능력이 중요하다. 다음 단계의 기술노트에서는 이런 통계 정보가 실제 조인 순서, range access, cost model 판단과 어떻게 이어지는지 더 깊게 연결해서 볼 수 있다.
