真实对比dictGet、普通JOIN、direct算法三种字典查找方式在500万行主表上的内存和耗时表现。
代码CREATE TABLE demo.dictsrc (id UInt64, name String) ENGINE=MergeTree ORDER BY id; INSERT INTO demo.dictsrc SELECT number, concat('name', toString(number)) FROM numbers(1000000); CREATE DICTIONARY demo.namedict (id UInt64, name String) PRIMARY KEY id SOURCE(CLICKHOUSE(TABLE 'dictsrc' DB 'demo')) LAYOUT(HASHED()) LIFETIME(MIN 300 MAX 600); SELECT k, dictGet('demo.namedict', 'name', k) FROM demo.jleft; -- dictGet SELECT jleft.k, name FROM demo.jleft LEFT JOIN demo.dictsrc ON jleft.k=dictsrc.id; -- 普通JOIN SELECT jleft.k, name FROM demo.jleft LEFT JOIN demo.namedict ON jleft.k=namedict.id SETTINGS join_algorithm='direct'; -- direct算法
dictGet() :真实内存 27,885,000 字节(约27.9MB),耗时 36ms 普通JOIN(join_algorithm=hash) :真实内存 124,768,407 字节(约124.8MB),耗时 34ms join_algorithm='direct' :真实内存 22,835,592 字节(约22.8MB),耗时 63ms
dictGet和direct两种方式真实都比普通JOIN省内存(分别省约4.5倍和5.5倍)——因为Dictionary的HASHED布局在查询开始前就已经把100万行数据加载并构建成一份常驻的哈希结构,查询时不需要像普通JOIN那样每次现场为右表重新构建一份哈希表。但direct算法虽然内存最省,耗时(63ms)反而比dictGet(36ms)和普通JOIN(34ms)都要长。
每一步都是本文上面用真实Dictionary跑出来的原始结果。
Dictionary(HASHED())、dictGet()、join_algorithm='direct'