HYPOTHETICAL INDEX
HYPOTHETICAL INDEX
가설 인덱스(hypothetical index)는 실제로 만들거나 저장하지 않고 MergeTree 계열 테이블에 붙일 수 있는 가상의 세션 범위 스킵 인덱스(skip index)예요. 그것은 현재 세션 안에서만 존재하며, EXPLAIN WHATIF가 실제 스킵 인덱스가 쿼리에 어떻게 영향을 줄지 추정하는 데 사용됩니다 — 일반적으로 스킵 비율(skip ratio, 건너뛸 수 있는 마크의 비율)과 마크 및 바이트 단위의 대략적인 비용입니다.
실제 인덱스를 디스크에 매터리얼라이즈하는 비용을 치르기 전에 가설 인덱스로 후보 인덱스를 평가해 보세요.
출처: 문서
본문
CREATE HYPOTHETICAL INDEX
CREATE HYPOTHETICAL INDEX [IF NOT EXISTS] name
ON [db.]table_name (expression) TYPE type[(args)] [GRANULARITY value]
문법은 ALTER TABLE ... ADD INDEX를 반영하지만, 인덱스는 만들어지거나 쓰여지지 않습니다 — 인덱스 설명만 현재 세션에 저장돼요.
name— 인덱스 이름; 이 세션의(database, table)내에서 고유해야 해요.expression— 인덱싱할 컬럼 또는 표현식이에요.TYPE type—minmax,set(N),bloom_filter(p),ngrambf_v1(...),tokenbf_v1(...).text와vector_similarity는 지원되지 않으며CREATE시점에 거부됩니다. 그것들의 실제ALTER TABLE ... ADD INDEX검증이 세션 전용 저장소가 복제할 수 없는 테이블 수준 설정에 의존하기 때문이에요.GRANULARITY value— 인덱스 그래뉼당 데이터 그래뉼 수. 기본값은 1이에요.
대상 테이블은 Atomic 데이터베이스의 MergeTree 계열 테이블이어야 합니다(UUID가 있어야 함). UUID가 없는 테이블 — 예를 들어 레거시 Ordinary 데이터베이스 또는 이전 문법 MergeTree — 은 세션 저장소가 가설 인덱스를 테이블 UUID로 키잉하기 때문에 거부됩니다.
Example
CREATE HYPOTHETICAL INDEX idx_b ON t (b) TYPE minmax GRANULARITY 1;
Evaluating a hypothetical index with EXPLAIN WHATIF
가설 인덱스를 정의하는 것만으로는 아무것도 안 됩니다. 쿼리에 어떻게 영향을 줄지 보려면 대표적인 SELECT에 EXPLAIN WHATIF를 실행하세요. 추정기는 각 후보 인덱스의 적용 가능성, 읽을 마크, 결과 스킵 비율, 그리고 추정이 어떻게 만들어졌는지(empirical, statistical, 또는 applicability_only)를 보고합니다.
CREATE TABLE t (a UInt64, b UInt64) ENGINE = MergeTree ORDER BY a
SETTINGS index_granularity = 100;
INSERT INTO t SELECT number, number FROM numbers(10000);
CREATE HYPOTHETICAL INDEX idx_b ON t (b) TYPE minmax GRANULARITY 1;
EXPLAIN WHATIF SELECT * FROM t WHERE b = 42;
결과:
Baseline (after PK + partition + existing indexes):
table: default.t
parts: 1
marks: 100
est_bytes: 85.52 KiB
With idx_b (minmax, hypothetical):
status: applicable
marks: 1
est_bytes: 875.00 B
skip_ratio: 99.0%
Estimation:
source: empirical
empirical_status: ok
sampled_parts: 1 / 1
sampled_marks: 100 / 100
elapsed_us: 631
est_bytes는 테이블의 평균 행 크기에서 나온 추정치이므로 정확한 수치는 저장소와 압축에 따라 달라져요.
인메모리 경험적(empirical) 스캔을 건너뛰고 컬럼 통계에서 추정하려면, 먼저 관련 컬럼에 정의하고(기본적으로 꺼져 있음), materialize mutation이 끝날 때까지 기다린 다음 경험적 경로를 비활성화하세요:
ALTER TABLE t ADD STATISTICS b TYPE tdigest;
ALTER TABLE t MATERIALIZE STATISTICS b SETTINGS mutations_sync = 1;
EXPLAIN WHATIF empirical = 0 SELECT * FROM t WHERE b < 10;
With idx_b (minmax, hypothetical):
status: applicable
marks: 1
est_bytes: 1.66 KiB
skip_ratio: 99.9%
Estimation:
source: statistical
empirical_status: disabled
전체 출력 스키마와 설정은 EXPLAIN WHATIF 참조를 보세요.
DROP HYPOTHETICAL INDEX
DROP HYPOTHETICAL INDEX [IF EXISTS] name ON [db.]table_name
현재 세션에서 가설 인덱스를 제거해요.
DROP ALL HYPOTHETICAL INDEXES
DROP ALL HYPOTHETICAL INDEXES
테이블과 무관하게 현재 세션에서 정의된 모든 가설 인덱스를 지워요.
Scope and lifetime
- 가설 인덱스는 현재 세션에서만 존재해요 — 다른 세션에는 보이지 않으며 세션이 끝나면 버려집니다.
- 하나를 정의하거나 버리는 것은 어떤 인덱스도 만들지 않으며 테이블에 대한 일반 쿼리에 절대 영향을 주지 않아요. 경험적
EXPLAIN WHATIF는 후보 인덱스를 메모리에 만들기 위해 테이블 데이터를 읽으며, 그 스캔은 세션의 읽기 제한과 쿼터에 포함됩니다. - 현재 세션의 가설 인덱스는
system.hypothetical_indexes로 검사하세요.
Limitations
text와 vector_similarity 후보는 CREATE HYPOTHETICAL INDEX 시점에 거부됩니다. 실제 검증이 세션 전용 저장소가 복제할 수 없는 테이블 수준 설정에 의존하기 때문이에요.
EXPLAIN WHATIF는 FINAL이 있는 쿼리에 대해 status: not_applicable을 보고하고(스킵 인덱스 프루닝이 PrimaryKeyExpand와 상호작용), 쿼리가 프로젝션에서 제공될 때 NOT_IMPLEMENTED로 오류를 냅니다(부모 테이블 인덱스는 프로젝션 파트에 매터리얼라이즈되지 않음).
경험적 skip_ratio는 상한입니다. 각 생존 그래뉼을 독립적으로 세고 seek-gap 통합(merge_tree_min_rows_for_seek / merge_tree_min_bytes_for_seek)을 모델링하지 않으며, 분리(OR) 술어 아래에서 후보와 기존 스킵 인덱스의 결합도 모델링하지 않아요. 따라서 실제 매터리얼라이즈된 인덱스는 조금 더 읽거나, 추정이 하지 않는 경우를 프루닝할 수 있습니다.
Required privileges
CREATE HYPOTHETICAL INDEX는 인덱스 표현식이 참조하는 컬럼에 대한 SELECT가 필요해요 — 컬럼 수준 SELECT(예: GRANT SELECT(b))로 충분합니다 — 경험적 EXPLAIN WHATIF가 그 컬럼들을 읽기 때문입니다.
DROP HYPOTHETICAL INDEX와 DROP ALL HYPOTHETICAL INDEXES는 추가 권한이 필요하지 않습니다. 세션 로컬 저장소에서 항목만 제거할 뿐이에요.