딕셔너리와 JOIN 중 언제 사용해야 하나요
WHERE 필터로 대부분의 행이 걸러지더라도 마찬가지입니다. 최근 버전(24.12+)에서는 많은 경우 JOIN 전에 필터를 푸시하지만, 그렇다고 해서 오버헤드가 항상 없어지는 것은 아닙니다. 반면 딕셔너리를 사용하면 dictGet을 인라인으로 호출하므로, 조회는 이미 필터링을 통과한 행에 대해서만 수행됩니다.
하지만 dictGet이 항상 적절한 선택은 아닙니다. 테이블에서 많은 비율의 행에 대해 dictGet을 호출해야 한다면 — 예를 들어 dictGet('dict', 'elevation', id) > 1800 같은 WHERE 조건에서 — 네이티브 인덱스를 사용할 수 있는 일반 컬럼을 쓰는 편이 더 나을 수 있습니다. 일반 컬럼의 경우 ClickHouse가 PREWHERE를 사용해 그래뉼을 건너뛸 수 있지만, dictGet은 인덱스 지원 없이 행 단위로 평가됩니다.
경험칙으로는 다음과 같습니다:
- 조회 키를 이미 알고 있는 작은 차원 테이블에 대한 JOIN을 대체할 때는 딕셔너리를 사용합니다.
- 많은 행에서 조회된 값을 기준으로 필터링해야 할 때는 일반 컬럼과 인덱스를 사용합니다.
레이아웃 선택
LAYOUT 절은 딕셔너리의 내부 데이터 구조를 제어합니다. 사용 가능한 모든 레이아웃은 레이아웃 참고에 문서화되어 있습니다.
레이아웃을 선택할 때는 다음 지침을 참고하십시오.
flat— 가장 빠른 레이아웃입니다(단순 배열 오프셋 조회). 하지만 키는UInt64여야 하며, 기본적으로 500,000개로 제한됩니다(max_array_size). 작거나 중간 규모의 테이블에서 단조 증가하는 정수 키에 가장 적합합니다. 희소 키 분포(예: 키 값이 1과 500,000인 경우)는 배열 크기가 가장 큰 키에 맞춰지므로 메모리를 낭비합니다. 500k 제한에 도달했다면hashed_array로 전환할 시점이라는 의미입니다.hashed_array— 대부분의 사용 사례에서 권장되는 기본 레이아웃입니다. 속성은 배열에 저장하고, 키를 배열 인덱스에 매핑하는 해시 테이블을 사용합니다.hashed와 거의 비슷한 속도를 제공하면서도, 특히 속성이 많을 때 메모리 효율이 더 좋습니다.hashed— 전체 딕셔너리를 해시 테이블에 저장합니다. 속성이 매우 적을 때는hashed_array보다 더 빠를 수 있지만, 속성 수가 늘어날수록 메모리 사용량이 더 커집니다.complex_key_hashed/complex_key_hashed_array— 키를UInt64로 CAST할 수 없을 때(예:String키) 사용합니다. 성능상의 절충점은 비복합 키 레이아웃과 동일합니다.sparse_hashed—hashed보다 메모리 사용량을 줄이는 대신 CPU를 더 사용합니다. 최선의 선택인 경우는 드물며, 단일 속성만 있을 때에만 효율적입니다. 대부분의 경우hashed_array가 더 적합합니다.cache/ssd_cache— 자주 액세스되는 키만 캐시합니다. 전체 데이터셋이 메모리에 들어가지 않을 때 유용하지만, 캐시 미스가 발생하면 조회가 원본 소스에 도달할 수 있습니다. 지연 시간에 민감한 workload에는 권장되지 않습니다.direct— 메모리에 저장하지 않고 매 조회마다 원본 소스를 쿼리합니다. 데이터가 너무 자주 변경되어 캐시하기 어렵거나, 딕셔너리가 메모리에 담기에는 너무 클 때 사용하십시오.
딕셔너리 사용 모니터링
system.dictionaries 테이블을 통해 메모리 사용량과 상태를 확인할 수 있습니다:
bytes_allocated— 딕셔너리가 사용하는 메모리입니다. 딕셔너리는 데이터를 압축하지 않은 상태로 저장하므로, 압축된 테이블 크기보다 훨씬 클 수 있습니다.hit_rate및found_rate—cache레이아웃의 효과를 평가하는 데 유용합니다.last_exception— 딕셔너리를 로드하지 못하거나 갱신에 실패할 때 이를 확인하십시오.