cached 字典布局类型会将字典存储在一个具有固定单元数的缓存中。
这些单元保存的是经常使用的元素。
字典键的类型为 UInt64。
查找字典时,会先查缓存。对于每个数据块,凡是在缓存中未命中或已过期的键,都会通过 SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...) 从源中请求。接收到的数据随后会写入缓存。
如果在字典中找不到键,则会创建缓存更新任务并将其加入更新队列。更新队列的属性可通过 max_update_queue_size、update_queue_push_timeout_milliseconds、query_wait_timeout_milliseconds、max_threads_for_updates 这些设置来控制。
对于 cache 字典,可以设置缓存中数据的过期 lifetime。如果某个单元中的数据自加载以来经过的时间超过了 lifetime,则该单元的值将不再使用,该键也会变为过期状态。下次需要使用该键时,会重新发起请求。此行为可通过 allow_read_expired_keys 设置进行配置。
这是所有字典存储方式中效率最低的一种。缓存的速度在很大程度上取决于设置是否正确以及具体的使用场景。cache 类型字典只有在命中率足够高时才能获得良好性能 (建议达到 99% 或更高) 。你可以在 system.dictionaries 表中查看平均命中率。
如果将 allow_read_expired_keys 设置为 1 (默认为 0) ,则字典支持异步更新。如果客户端请求的键都在缓存中,但其中部分已过期,则字典会先向客户端返回这些过期键,同时异步从源中重新请求它们。
要提升缓存性能,请使用带 LIMIT 的子查询,并从字典外部调用该函数。
支持所有类型的源。
设置示例:
LAYOUT(CACHE(SIZE_IN_CELLS 1000000000))<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>请将缓存大小设置得足够大。你需要通过试验来确定单元数:
- 先设置一个值。
- 运行查询,直到缓存被完全填满。
- 使用
system.dictionaries表评估内存消耗。 - 增加或减少单元数,直到达到所需的内存消耗。