> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-parallel-read-in-order-multi-part.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# cache 딕셔너리 레이아웃

> 고정 크기의 인메모리 캐시에 딕셔너리를 저장합니다.

`cached` 딕셔너리 레이아웃 유형은 고정된 개수의 셀을 가진 캐시에 딕셔너리를 저장합니다.
이 셀에는 자주 사용되는 요소가 들어 있습니다.

딕셔너리 키는 [UInt64](/ko/reference/data-types/int-uint) 타입입니다.

딕셔너리를 조회할 때는 먼저 캐시를 확인합니다. 각 데이터 블록에 대해 캐시에서 찾지 못했거나 오래된 키는 모두 `SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...)`를 사용해 소스에 요청합니다. 받은 데이터는 이후 캐시에 기록됩니다.

이는 키를 **조회**하는 경우, 즉 `dictGet` 및 기타 딕셔너리 함수에 해당합니다. `SELECT ... FROM <dictionary>`로 딕셔너리를 **테이블처럼** 읽는 것은 다릅니다. 캐시는 어떤 키가 존재하는지에 대한 기록을 보관하지 않기 때문에, 이러한 읽기는 그 시점에 캐시에 상주하면서 값을 보유하고 있는 셀만 열거하며, 키에 대한 `WHERE` 조건은 가져올 키의 목록이 아니라 그 셀들에 대한 일반 필터로 동작합니다. 캐시에 없는 키는 `WHERE` 조건이 무엇이든 이 방식으로는 발견할 수 없습니다. 조회된 *적은* 있지만 소스에서 찾지 못한 키도 보이지 않습니다. 캐시는 그 미스를 기본값 셀로 기억하며, 테이블 읽기는 기본값 셀을 건너뛰기 때문입니다. 상주 중인 셀이라고 해서 소스와 무관한 것도 아닙니다. 만료된 셀은 `dictGet`과 동일한 경로로 읽히므로 소스에 다시 요청됩니다. 이때 요청은 동기적으로, 또는 `allow_read_expired_keys`가 활성화되어 있으면 비동기적으로 이루어집니다.

```sql theme={null}
CREATE DICTIONARY cache_dict (id UInt64, data String) PRIMARY KEY id
SOURCE(CLICKHOUSE(TABLE 'cache_src')) LIFETIME(MIN 0 MAX 900) LAYOUT(CACHE(SIZE_IN_CELLS 1000));

-- nothing is cached yet, so nothing comes back and the source is not queried
SELECT count() FROM cache_dict WHERE id IN (1, 2, 3);
0

-- looking the keys up populates the cache
SELECT dictGet('cache_dict', 'data', toUInt64(number + 1)) FROM numbers(3);

-- and now the same read sees them
SELECT count() FROM cache_dict WHERE id IN (1, 2, 3);
3
```

따라서 cache 딕셔너리는 딕셔너리 함수를 통해 사용하도록 설계되었습니다. 임의의 키 조회가 항상 소스까지 도달해야 한다면, 조회마다 소스를 쿼리하고 아무것도 캐시하지 않는 [direct](/ko/reference/statements/create/dictionary/layouts/direct) 레이아웃과 함께 `dictGet`을 사용하십시오. 단, `direct` 딕셔너리를 테이블처럼 읽는 것 역시 키 기반 가져오기가 아닙니다. ClickHouse는 키 필터를 딕셔너리로 푸시하지 않기 때문에, `SELECT ... FROM <dictionary> WHERE key IN (...)`는 소스 전체를 로드한 뒤에 필터링합니다. 딕셔너리를 테이블처럼 읽으려면 [flat](/ko/reference/statements/create/dictionary/layouts/flat)이나 [hashed](/ko/reference/statements/create/dictionary/layouts/hashed)처럼 전체를 보관하는 레이아웃을 사용하십시오.

딕셔너리에서 키를 찾지 못하면 캐시 업데이트 작업이 생성되어 업데이트 큐에 추가됩니다. 업데이트 큐 속성은 `max_update_queue_size`, `update_queue_push_timeout_milliseconds`, `query_wait_timeout_milliseconds`, `max_threads_for_updates` 설정으로 제어할 수 있습니다.

cache 딕셔너리에서는 캐시에 있는 데이터의 만료 [lifetime](/ko/reference/statements/create/dictionary/lifetime)을 설정할 수 있습니다. 셀에 데이터가 로드된 뒤 `lifetime`보다 더 많은 시간이 지나면 해당 셀의 값은 사용되지 않으며 키는 만료된 상태가 됩니다. 이 키는 다음에 필요할 때 다시 요청됩니다. 이 동작은 `allow_read_expired_keys` 설정으로 구성할 수 있습니다.

이 방식은 딕셔너리를 저장하는 모든 방법 중 가장 비효율적입니다. 캐시 속도는 올바른 설정과 사용 시나리오에 크게 좌우됩니다. cache 유형 딕셔너리는 적중률이 충분히 높을 때만 좋은 성능을 냅니다(권장: 99% 이상). 평균 적중률은 [system.dictionaries](/ko/reference/system-tables/dictionaries) 테이블에서 확인할 수 있습니다.

`allow_read_expired_keys` 설정을 1로 지정하면(기본값은 0) 딕셔너리에서 비동기 업데이트를 지원할 수 있습니다. 클라이언트가 키를 요청했고 그 키가 모두 캐시에 있지만 일부가 만료된 경우, 딕셔너리는 클라이언트에 만료된 키를 반환하고 소스에 비동기적으로 다시 요청합니다.

캐시 성능을 높이려면 `LIMIT`가 있는 서브쿼리를 사용하고, 딕셔너리 함수를 외부에서 호출하십시오.

모든 유형의 소스가 지원됩니다.

설정 예시:

<Tabs>
  <Tab title="DDL">
    ```sql theme={null}
    LAYOUT(CACHE(SIZE_IN_CELLS 1000000000))
    ```
  </Tab>

  <Tab title="설정 파일">
    ```xml theme={null}
    <layout>
        <cache>
            <!-- 셀 수 기준 캐시 크기입니다. 2의 거듭제곱으로 올림됩니다. -->
            <size_in_cells>1000000000</size_in_cells>
            <!-- 만료된 키 읽기를 허용합니다. -->
            <allow_read_expired_keys>0</allow_read_expired_keys>
            <!-- 업데이트 큐의 최대 크기입니다. -->
            <max_update_queue_size>100000</max_update_queue_size>
            <!-- 업데이트 작업을 큐에 넣을 때의 최대 제한 시간(밀리초)입니다. -->
            <update_queue_push_timeout_milliseconds>10</update_queue_push_timeout_milliseconds>
            <!-- 업데이트 작업이 완료되기를 기다리는 최대 제한 시간(밀리초)입니다. -->
            <query_wait_timeout_milliseconds>60000</query_wait_timeout_milliseconds>
            <!-- cache 딕셔너리 업데이트용 최대 스레드 수입니다. -->
            <max_threads_for_updates>4</max_threads_for_updates>
        </cache>
    </layout>
    ```
  </Tab>
</Tabs>

<br />

캐시 크기는 충분히 크게 설정하십시오. 셀 수를 정하려면 실험이 필요합니다:

1. 값을 하나 설정합니다.
2. 캐시가 완전히 찰 때까지 쿼리를 실행합니다.
3. `system.dictionaries` 테이블을 사용해 메모리 사용량을 평가합니다.
4. 필요한 메모리 사용량에 도달할 때까지 셀 수를 늘리거나 줄입니다.

<Note>
  이 레이아웃의 소스로는 ClickHouse를 권장하지 않습니다. 딕셔너리 조회에는 임의 지점 읽기가 필요하지만, 이는 ClickHouse가 최적화된 접근 패턴이 아닙니다.
</Note>
