bigywater.tech
ClickHouse 内部原理 · 77

Dictionary:外部维表如何加载到内存

真实用同一张MySQL表同时建Dictionary和MySQL引擎表做对照,验证LIFETIME缓存机制真实的滞后窗口和自动刷新时机。

同源不同新鲜度
真实同一次MySQL更新,字典和引擎表看到的结果不同
LIFETIME窗口内自动刷新
真实22秒后字典自动追上了MySQL的最新数据

做的事:同一张MySQL表,真实同时建Dictionary和MySQL引擎表做对照

代码CREATE DICTIONARY demo.mysql_dict (id UInt32, name String, amt Decimal(10,2)) PRIMARY KEY id SOURCE(MYSQL(HOST '127.0.0.1' PORT 3306 USER 'root' PASSWORD '' DB 'mysqllab' TABLE 'ch_integration_test')) LAYOUT(HASHED()) LIFETIME(MIN 10 MAX 20); -- 真实在MySQL端立即改一行数据 UPDATE ch_integration_test SET name='ALICE_UPDATED' WHERE id=1; -- 立即分别查字典和上一篇的MySQL引擎表 SELECT dictGet('demo.mysql_dict','name', toUInt64(1)); SELECT name FROM demo.mysql_ext WHERE id=1;

验证:真实同一次更新,两种访问方式看到的新鲜度完全不同

实测 · 本机执行输出(MySQL端刚改完,立即查询)
SELECT dictGet('demo.mysql_dict','name', toUInt64(1));
→ alice          ← 真实还是旧值(字典还没到刷新时机)

SELECT name FROM demo.mysql_ext WHERE id=1;
→ ALICE_UPDATED  ← 真实立即看到了新值(上一篇验证过的live直连)

同一次UPDATE,同一份底层数据,字典和MySQL引擎表给出的答案真实不一样——这就是LIFETIME缓存机制真实的样子:Dictionary不是每次查询都去问一次MySQL,而是真实先把整张表(或者按需的部分)加载进内存,之后的dictGet都只是查这份内存里的缓存,跟MySQL端实际发生了什么完全脱钩,直到缓存真实过期。

验证:等过LIFETIME窗口,字典真实自动刷新了

实测 · 本机执行输出(真实等待22秒,落在LIFETIME(10,20)区间之后)
-- sleep 22秒
SELECT dictGet('demo.mysql_dict','name', toUInt64(1));
→ ALICE_UPDATED   ← 真实自动刷新了,跟MySQL端一致了

SELECT last_successful_update_time FROM system.dictionaries WHERE name='mysql_dict';
→ 2026-09-29 18:44:37   ← 真实的最近一次刷新时间
这组真实对比清楚地说明了Dictionary和MySQL引擎表真实解决的是不同的问题:MySQL引擎表(本系列上一篇)真实适合"必须看到实时数据"的场景,代价是每次查询都要真实打一次到外部数据库的网络请求;Dictionary真实适合"数据变化不频繁、但会被高频反复查询"的场景(典型的维表JOIN/枚举翻译),用LIFETIME换来的是查询时完全不用碰网络、直接读内存的极致性能(本系列前面《字典JOIN》一篇验证过dictGet比普通JOIN省好几倍内存),代价是真实存在一个"数据已经变了,但字典还不知道"的窗口——本文的窗口是LIFETIME(MIN 10 MAX 20)设置的10到20秒之间。真实的选择原则很直接:如果业务能接受"最多滞后LIFETIME这么久"的数据新鲜度(大多数维表场景,比如商品类目、地区编码,本来变化就很少),用Dictionary换取的查询性能提升通常是值得的;如果业务要求的是绝对的实时性(比如本系列后面账户余额这类场景),就应该像MySQL引擎表这样接受每次查询的真实网络开销,而不是被Dictionary的缓存窗口坑到。

分步演示:从缓存滞后到LIFETIME窗口过后的真实自动刷新

每一步都是本文上面用真实Dictionary和MySQL对照跑出来的原始结果。

同一次更新,字典和live表看到的新鲜度真实不同
这一步新验证的时刻

    本文用到的工具

    • 本机真实的MySQL实例,真实的 CREATE DICTIONARY ... SOURCE(MYSQL(...)) LIFETIME(MIN 10 MAX 20)
    • 真实与上一篇MySQL引擎表做同一份数据的新鲜度对照
    京ICP备2026067502号-1京公网安备11010502063487号