본문으로 건너뛰기
최종 수정: 에

통계

통계는 Doris CBO(Cost-Based Optimizer)의 비용 추정 기반이며, 통계의 정확도는 쿼리 실행 계획의 품질을 직접적으로 좌우합니다. 이 문서에서는 통계 수집 방법, 관리 명령, 관련 설정, 일반적인 문제 해결 방법을 소개합니다.

적용 버전: Doris 2.0 이상.

사전 확인 사항​

  • 사용 중인 Doris 버전을 알고 있습니다(자동 수집 기능은 2.0.3 이상 필요).
  • 대상 객체의 유형을 확인했습니다: 내부 테이블, Hive, Iceberg, Paimon, JDBC 등.
  • 대상 컬럼의 타입을 알고 있습니다(기본 타입만 수집 지원).
  • 수집을 수동으로 실행할지, 자동 수집을 사용할지 결정했습니다.

핵심 개념 한눈에 보기​

한 문장 정의: 통계는 Doris가 테이블과 컬럼 수준에서 기록하는 데이터 분포 메타데이터로, 옵티마이저가 비용을 추정하고 최적의 실행 계획을 선택하는 데 사용합니다.

Doris는 테이블 수준에서 컬럼별로 통계를 수집하며, 다음 지표를 포함합니다:

지표설명
row_count전체 행 수
data_size컬럼의 전체 데이터 크기
avg_size_byte컬럼의 행당 평균 데이터 크기
ndv고유 값 수(카디널리티)
min최솟값
max최댓값
null_countnull 값 수

지원하는 컬럼 타입: BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, FLOAT, DOUBLE, DATE, DATETIME, TIMESTAMP_NS, STRING, VARCHAR, TEXT.

지원하지 않는 타입(자동으로 건너뜀): JSONB, VARIANT, MAP, STRUCT, ARRAY, HLL, BITMAP, TIME, TIMEV2, VARBINARY.

수집 결과는 internal.__internal_schema.column_statistics 테이블에 저장됩니다.

통계 수집​

Doris는 기본적으로 내부 테이블의 자동 샘플링 수집을 활성화하므로, 대부분의 경우 수동으로 개입할 필요가 없습니다. 세밀하게 제어하려면 수동 수집을 사용하세요.

수집 방식 비교​

구분수동 수집(ANALYZE)자동 수집(기본 활성화)
실행 계기사용자가 실행백그라운드 스레드가 주기적으로 스캔
사용 사례긴급 업데이트, 최초 수집, 디버깅정기적인 유지 관리, 장기적인 최신 상태 유지
최소 버전2.02.0.3
샘플링 전략행 수 또는 비율 지정기본적으로 4194304행(2^22) 샘플링
제어 단위테이블 / 데이터베이스 / 컬럼클러스터 수준 스위치 + 테이블 수준 정책

수동 수집​

목적: 테이블 또는 데이터베이스의 통계 수집과 갱신을 즉시 실행합니다.

명령: ANALYZE 문으로 수집 작업을 수동 제출합니다. 자세한 내용은 SQL 매뉴얼의 ANALYZE를 참조하세요.

대표적인 예시:

lineitem 테이블의 모든 컬럼에 대해 전체 수집을 수행합니다:

ANALYZE TABLE lineitem;

tpch100 데이터베이스에 있는 모든 테이블의 모든 컬럼에 대해 전체 수집을 수행합니다:

ANALYZE DATABASE tpch100;

lineitem 테이블에서 100000행을 샘플링하여 수집합니다:

ANALYZE TABLE lineitem WITH SAMPLE ROWS 100000;

l_orderkey와 l_linenumber 컬럼에 대해 lineitem 테이블에서 100000행을 샘플링하여 수집합니다:

ANALYZE TABLE lineitem (l_orderkey, l_linenumber) WITH SAMPLE ROWS 100000;

Hot Value 수집​

Hot Value는 컬럼에 자주 나타나는 값을 컬럼 통계에 기록합니다. 이를 통해 옵티마이저가 편향된 데이터에 대한 조건식을 더 정확하게 추정할 수 있지만, 카디널리티가 높은 컬럼에서 수집하면 메모리를 더 많이 사용할 수 있습니다.

수동 전체 수집 시에는 WITH HOT VALUE를 사용하여 Hot Value를 수집합니다:

ANALYZE TABLE lineitem WITH SYNC WITH HOT VALUE;

WITH HOT VALUE를 WITH SAMPLE과 함께 사용하지 마세요. 샘플링 수집에서는 항상 Hot Value를 수집하므로, 이 옵션을 WITH SAMPLE과 함께 지정하면 거부됩니다. WITH HOT VALUE를 지정하지 않으면 Doris는 기존 동작을 유지합니다:

수집 방식Hot Value 수집
전체 수집비활성화
샘플링 수집항상 활성화

자동 수집​

목적: 백그라운드 스레드가 주기적으로 스캔하여 통계를 자동으로 최신 상태로 유지합니다.

스위치: ENABLE_AUTO_ANALYZE 변수로 제어합니다.

SET GLOBAL ENABLE_AUTO_ANALYZE = TRUE;  -- Enable auto collection
SET GLOBAL ENABLE_AUTO_ANALYZE = FALSE; -- Disable auto collection

동작 메커니즘​

활성화하면 백그라운드 스레드가 InternalCatalog 아래의 모든 데이터베이스와 테이블을 주기적으로 스캔합니다. 각 폴링 라운드에서는 다음 규칙에 따라 재수집 여부를 결정합니다:

  1. 테이블에 통계가 없는 컬럼이 있습니다.
  2. 테이블의 상태 점수가 임계값보다 낮습니다(기본값 90, table_stats_health_threshold로 제어). 상태 점수가 100에 가까울수록 데이터 변경량이 적으며, 90 미만이면 통계가 실제 데이터에서 크게 벗어나 재수집이 필요하다는 의미입니다.
  3. 내부 테이블의 경우, 데이터가 변경되었지만 최근 24시간 동안 통계가 수집되지 않았습니다.

폴링 간격: 기본값은 5분이며, auto_check_statistics_in_minutes를 fe.conf에서 설정합니다. 클러스터가 시작된 뒤 5분 후 첫 번째 라운드가 시작되며, 각 라운드가 끝나면 스레드는 5분 동안 대기한 후 다음 라운드를 시작합니다.

참고

한 라운드에 필요한 시간은 테이블 수와 데이터 양에 따라 달라지므로, 특정 테이블의 통계가 5분 이내에 수집된다고 보장할 수는 없습니다.

주요 매개변수​

매개변수용도기본값
auto_analyze_table_width_threshold자동 수집 대상 테이블의 최대 컬럼 수300
huge_table_default_sample_rows자동 수집 시 샘플링할 행 수4194304 (2^22)
auto_analyze_start_time자동 수집 시작 시간0:00:00
auto_analyze_end_time자동 수집 종료 시간23:59:59

컬럼 수 제한 조정(컬럼이 많은 테이블의 과도한 리소스 사용 방지):

SET GLOBAL auto_analyze_table_width_threshold = 350;

사용량이 적은 시간대에 실행(서비스에 미치는 영향 방지):

SET GLOBAL auto_analyze_start_time = "03:00:00"; -- Start time: 3:00 AM
SET GLOBAL auto_analyze_end_time = "14:00:00"; -- End time: 2:00 PM

더 정확한 데이터 분포 정보를 얻으려면 huge_table_default_sample_rows를 높여 샘플링할 행 수를 늘릴 수 있습니다.

외부 테이블 통계 수집​

외부 테이블 유형: 일반적으로 Hive, Iceberg, JDBC, Paimon 등이 있습니다.

기능 지원 표​

외부 테이블 유형수동 전체 수집수동 샘플링자동 수집
Hive지원지원지원
Iceberg지원미지원미지원
JDBC지원미지원미지원
기타미지원미지원미지원

기본 동작​

외부 Catalog는 기본적으로 컬럼 통계 자동 수집에 참여하지 않습니다. 과거 데이터에 대한 과도한 스캔을 방지하기 위해 테이블의 행 수만 수집합니다. 컬럼 통계 자동 수집을 활성화하려면 다음을 실행합니다:

ALTER CATALOG <catalog_name> SET PROPERTIES ('enable.auto.analyze'='true');  -- Enable
ALTER CATALOG <catalog_name> SET PROPERTIES ('enable.auto.analyze'='false'); -- Disable

테이블 수준 제어(Catalog 속성보다 우선 적용):

ALTER TABLE <table_name> SET ("auto_analyze_policy" = "enable");          -- Enable
ALTER TABLE <table_name> SET ("auto_analyze_policy" = "disable"); -- Disable
ALTER TABLE <table_name> SET ("auto_analyze_policy" = "base_on_catalog"); -- Follow the catalog

외부 테이블에는 상태 점수 개념이 없습니다. 자동 수집을 활성화하면 기본적으로 외부 테이블의 통계는 24시간 동안 한 번만 자동 수집됩니다. 최소 간격은 external_table_auto_analyze_interval_in_millis로 조정할 수 있습니다.

행 수 추정 전략​

외부 테이블 유형추정 방법
Hive먼저 Parameters의 numRows를 사용하고, 없으면 totalSize와 스키마를 함께 사용하여 추정하며, 이 값도 없으면 파일 크기를 기준으로 추정
Iceberg스냅샷 API를 호출하여 계산에 필요한 total-records와 total-position-deletes를 가져옴
Paimonscan API를 호출하여 각 split의 행 수를 합산
JDBC백엔드 데이터베이스의 행 수 조회 구문으로 가져옴(MySQL, Oracle, PostgreSQL, SQLServer 지원)
기타자동 조회 및 추정은 아직 지원하지 않음

파일 크기 스캔에 따른 리소스 사용이 우려된다면 Hive의 파일 크기 기반 추정을 비활성화할 수 있습니다:

SET GLOBAL enable_get_row_count_from_file_list = FALSE;

외부 테이블의 추정 행 수를 확인합니다:

SHOW TABLE STATS table_name;
팁

row_count가 -1이면 행 수를 가져올 수 없거나 테이블이 비어 있다는 의미입니다.

통계 작업 관리​

통계 작업 조회​

목적: 제출된 비동기 통계 수집 작업을 조회합니다(동기 작업은 이력을 보관하지 않음).

명령:

SHOW ANALYZE [job_id];

자세한 내용은 SHOW ANALYZE를 참조하세요.

참고: 시스템은 작업 이력을 20000개까지만 보관합니다. 출력 컬럼의 의미는 다음과 같습니다:

컬럼설명
job_id통계 작업 ID
catalog_nameCatalog 이름
db_name데이터베이스 이름
tbl_name테이블 이름
col_name컬럼 이름 목록(index_name:column_name)
job_type작업 유형
analysis_type통계 유형
message작업 메시지
state작업 상태
progress작업 진행 상황
schedule_type스케줄링 유형
start_time작업 시작 시간
end_time작업 종료 시간

예시:

mysql> SHOW ANALYZE 245073\G
*************************** 1. row ***************************
job_id: 93021
catalog_name: internal
db_name: tpch
tbl_name: region
col_name: [region:r_regionkey,region:r_comment,region:r_name]
job_type: MANUAL
analysis_type: FUNDAMENTALS
message:
state: FINISHED
progress: 3 Finished | 0 Failed | 0 In Progress | 3 Total
schedule_type: ONCE
start_time: 2024-07-11 15:15:00
end_time: 2024-07-11 15:15:33

통계 태스크 조회​

목적: 각 작업에는 여러 태스크가 포함될 수 있으며, 각 태스크는 하나의 컬럼에 대응합니다. 태스크 수준의 진행 상황을 확인할 수 있습니다.

명령:

SHOW ANALYZE TASK STATUS [job_id];

예시:

mysql> SHOW ANALYZE TASK STATUS 93021;
+---------+-------------+------------+---------+------------------------+-----------------+----------+
| task_id | col_name | index_name | message | last_state_change_time | time_cost_in_ms | state |
+---------+-------------+------------+---------+------------------------+-----------------+----------+
| 93022 | r_regionkey | region | | 2024-07-11 15:15:33 | 32883 | FINISHED |
| 93023 | r_comment | region | | 2024-07-11 15:15:33 | 32883 | FINISHED |
| 93024 | r_name | region | | 2024-07-11 15:15:33 | 32883 | FINISHED |
+---------+-------------+------------+---------+------------------------+-----------------+----------+

컬럼 통계 조회​

목적: 수집된 컬럼 수준 통계를 조회합니다.

명령:

SHOW COLUMN [cached] STATS table_name [ (column_name [, ...]) ];

매개변수:

매개변수설명
cachedFE 메모리 캐시에 있는 통계만 표시
table_name대상 테이블. db_name.table_name 형식으로 지정 가능
column_name대상 컬럼(쉼표로 구분하여 여러 컬럼 지정 가능). 지정하지 않으면 모든 컬럼 표시

예시:

mysql> SHOW COLUMN STATS region (r_regionkey)\G
*************************** 1. row ***************************
column_name: r_regionkey
index_name: region
count: 5.0
ndv: 5.0
num_null: 0.0
data_size: 20.0
avg_size_byte: 4.0
min: 0
max: 4
method: FULL
type: FUNDAMENTALS
trigger: MANUAL
query_times: 0
updated_time: 2024-07-11 15:15:33
1 row in set (0.36 sec)

테이블 통계 개요 조회​

목적: 테이블 수준의 통계 수집 개요를 조회합니다.

명령:

SHOW TABLE STATS table_name;

table_name은 db_name.table_name 형식으로 지정할 수 있습니다.

출력 컬럼:

컬럼설명
updated_rows마지막 ANALYZE 이후 이 테이블에서 갱신된 행 수
query_times향후 버전에서 쿼리 횟수를 기록하기 위해 예약된 컬럼
row_count테이블의 행 수(명령 실행 시점의 정확한 행 수를 반영하지 않을 수 있음)
updated_time통계가 마지막으로 갱신된 시간
columns통계가 수집된 컬럼
trigger통계 수집이 실행된 방식
new_partition새 파티션에 처음으로 데이터가 적재되었는지 여부
user_inject사용자가 통계를 수동으로 주입했는지 여부

통계 작업 종료​

목적: 현재 실행 중인 비동기 통계 작업을 종료합니다.

명령:

KILL ANALYZE job_id;

job_id는 비동기 ANALYZE 실행 시 반환되는 값이며, SHOW ANALYZE로도 확인할 수 있습니다.

예시: ID가 52357인 통계 작업을 종료합니다.

mysql> KILL ANALYZE 52357;

통계 삭제​

목적: 아직 존재하는 테이블의 통계를 수동으로 정리합니다. 삭제된 객체의 통계는 백그라운드에서 주기적으로 정리되므로 수동 작업이 필요하지 않습니다.

명령:

DROP STATS table_name;

세션 변수 및 설정 항목​

세션 변수​

세션 변수설명기본값
auto_analyze_start_time자동 수집 시작 시간0:00:00
auto_analyze_end_time자동 수집 종료 시간23:59:59
enable_auto_analyze자동 수집 활성화 여부TRUE
huge_table_default_sample_rows대용량 테이블에서 샘플링할 행 수4194304
table_stats_health_threshold범위는 0-100. 데이터가 (100 - 임계값)%만큼 변경되면 통계가 오래된 것으로 간주90
auto_analyze_table_width_threshold자동 수집 대상 테이블의 최대 컬럼 수. 이를 초과하는 테이블은 제외300
enable_get_row_count_from_file_list파일 크기를 기준으로 Hive 테이블의 행 수를 추정할지 여부TRUE (2.1.5 이전의 기본값은 FALSE)

FE 설정 항목​

참고

다음 FE 설정 항목은 일반적으로 특별히 신경 쓸 필요가 없습니다.

FE 설정 항목설명기본값
analyze_record_limit영구 저장할 통계 작업 실행 기록 수 제어20000
stats_cache_sizeFE 측 통계 캐시의 항목 수500000
statistics_simultaneously_running_task_num동시에 실행할 수 있는 비동기 통계 작업 수3
statistics_sql_mem_limit_in_bytes각 통계 SQL이 사용할 수 있는 BE 메모리2L * 1024 * 1024 (2 GiB)

자주 묻는 질문(FAQ)​

Q1: 테이블의 통계가 수집되었는지 어떻게 확인하나요?​

단계 1: 수집 결과가 있는지 확인합니다.

SHOW COLUMN STATS table_name;

단계 2: 통계가 FE 캐시에 로드되어 있는지 확인합니다.

SHOW COLUMN CACHED STATS table_name;

두 결과가 모두 비어 있다면 현재 테이블에 통계가 없는 것입니다. 통계가 수집된 경우의 출력 예시는 다음과 같습니다:

mysql> SHOW COLUMN CACHED STATS mvTestDup;
+-------------+------------+-------+------+----------+-----------+---------------+------+------+--------+--------------+---------+-------------+---------------------+
| column_name | index_name | count | ndv | num_null | data_size | avg_size_byte | min | max | method | type | trigger | query_times | updated_time |
+-------------+------------+-------+------+----------+-----------+---------------+------+------+--------+--------------+---------+-------------+---------------------+
| key1 | mvTestDup | 6.0 | 4.0 | 0.0 | 48.0 | 8.0 | 1 | 1001 | FULL | FUNDAMENTALS | MANUAL | 0 | 2024-07-22 10:53:25 |
| key2 | mvTestDup | 6.0 | 4.0 | 0.0 | 48.0 | 8.0 | 2 | 2001 | FULL | FUNDAMENTALS | MANUAL | 0 | 2024-07-22 10:53:25 |
| value2 | mvTestDup | 6.0 | 4.0 | 0.0 | 24.0 | 4.0 | 4 | 4001 | FULL | FUNDAMENTALS | MANUAL | 0 | 2024-07-22 10:53:25 |
| value1 | mvTestDup | 6.0 | 4.0 | 0.0 | 24.0 | 4.0 | 3 | 3001 | FULL | FUNDAMENTALS | MANUAL | 0 | 2024-07-22 10:53:25 |
| mv_key1 | mv1 | 6.0 | 4.0 | 0.0 | 48.0 | 8.0 | 1 | 1001 | FULL | FUNDAMENTALS | MANUAL | 0 | 2024-07-22 10:53:25 |
| value3 | mvTestDup | 6.0 | 4.0 | 0.0 | 24.0 | 4.0 | 5 | 5001 | FULL | FUNDAMENTALS | MANUAL | 0 | 2024-07-22 10:53:25 |
+-------------+------------+-------+------+----------+-----------+---------------+------+------+--------+--------------+---------+-------------+---------------------+
6 rows in set (0.00 sec)

단계 3: SQL을 수동으로 실행하여 정확도를 검증합니다.

SELECT count(1), ndv(col1), min(col1), max(col1) FROM table;

count와 ndv의 규모 차이가 한 자릿수 이내이면 정확도는 허용할 만한 수준입니다.

Q2: 테이블의 통계가 자동으로 수집되지 않는 이유는 무엇인가요?​

확인 1: 자동 수집 스위치가 켜져 있는지 확인합니다.

SHOW VARIABLES LIKE "enable_auto_analyze";
-- If false, enable it:
SET GLOBAL enable_auto_analyze = TRUE;

확인 2: 테이블의 컬럼 수가 auto_analyze_table_width_threshold(기본값 300)를 초과하는지 확인합니다. 이를 초과하는 테이블은 자동 수집에서 제외됩니다.

SHOW VARIABLES LIKE "auto_analyze_table_width_threshold";
-- If smaller than the table width, adjust:
SET GLOBAL auto_analyze_table_width_threshold = 350;

확인 3: 다른 작업이 실행 중인지 확인합니다.

SHOW AUTO ANALYZE;

자동 수집은 단일 스레드에서 순차적으로 실행되며 모든 데이터베이스와 테이블을 순회하므로, 전체 순회 주기가 길어질 수 있습니다.

Q3: 일부 컬럼에 통계가 없는 이유는 무엇인가요?​

기본 타입 컬럼만 통계 수집을 지원합니다. 복합 타입(JSONB, VARIANT, MAP, STRUCT, ARRAY, HLL, BITMAP, TIME, TIMEV2, VARBINARY 등)은 자동으로 건너뜁니다.

Q4: 오류 Stats table not available, please make sure your cluster status is normal​

일반적으로 내부 통계 테이블이 비정상 상태임을 의미합니다. 문제 해결 단계는 다음과 같습니다:

단계 1: 모든 BE가 정상 상태인지 확인합니다.

단계 2: 통계 테이블의 모든 tabletId를 확인합니다.

SHOW TABLETS FROM internal.__internal_schema.column_statistics;

단계 3: tablet을 하나씩 진단합니다.

ADMIN DIAGNOSE TABLET tablet_id;

단계 4: 비정상 tablet을 복구한 후 통계를 다시 수집합니다.

Q5: 통계 수집이 제때 이루어지지 않으면 어떻게 하나요?​

  • 긴급한 상황: 대상 테이블에서 ANALYZE를 수동으로 실행합니다.
  • 상태 임계값 조정: 기본값인 table_stats_health_threshold = 90은 데이터가 10% 넘게 변경된 경우에만 수집이 실행된다는 의미입니다. 이 값을 95로 높이면 5% 넘게 변경되었을 때 수집이 실행됩니다:
SET GLOBAL table_stats_health_threshold = 95;

Q6: 자동 수집이 리소스를 너무 많이 사용하면 어떻게 하나요?​

자동 수집은 샘플링을 사용하고 단일 스레드에서 순차적으로 실행되므로, 일반적으로 리소스 사용량을 제어할 수 있습니다. 다만 다음과 같은 경우에는 메모리 사용량이 높아질 수 있습니다:

  • 파티션 수가 많은 테이블.
  • 개별 tablet의 크기가 매우 큰 테이블.

최적화 권장 사항:

  1. 테이블 생성 시 tablet 수를 적절히 계획하고 지나치게 큰 tablet이 생기지 않도록 합니다.
  2. 시스템 사용량이 적은 시간대에 자동 수집을 활성화합니다(auto_analyze_start_time / auto_analyze_end_time 참조).
  3. 대용량 테이블은 사용량이 적은 시간대에 수동으로 수집합니다.
  4. Doris 3.x 계열에서는 이러한 상황에 대한 최적화가 더욱 개선될 예정입니다.