真实对比默认设置下WHERE和显式PREWHERE的执行计划,发现两者完全相同,再手动关掉自动优化验证背后的真实原因。
代码CREATE TABLE demo.pw2 (k UInt64, flag UInt8, payload String) ENGINE=MergeTree ORDER BY k; INSERT INTO demo.pw2 SELECT number, number<10000, repeat('x',500) FROM numbers(2000000); EXPLAIN actions=1 SELECT sum(length(payload)) FROM demo.pw2 WHERE flag=1; EXPLAIN actions=1 SELECT sum(length(payload)) FROM demo.pw2 PREWHERE flag=1;
-- 普通WHERE,什么SETTINGS都没加:
EXPLAIN actions=1 SELECT sum(length(payload)) FROM demo.pw2 WHERE flag=1;
→ ReadFromMergeTree (demo.pw2)
Output: payload.size
Prewhere filter
Prewhere filter column: flag = 1 ← 注意:WHERE被自动改写成了Prewhere filter
-- 显式PREWHERE:
EXPLAIN actions=1 SELECT sum(length(payload)) FROM demo.pw2 PREWHERE flag=1;
→ ReadFromMergeTree (demo.pw2)
Output: payload.size
Prewhere filter
Prewhere filter column: flag = 1 ← 真实完全一样的计划
SELECT value, changed FROM system.settings WHERE name='optimize_move_to_prewhere';
→ 1 0 ← 真实默认值就是1(开启),不用手动设置两条EXPLAIN的输出真实一字不差。原因就在最后一条查询里:optimize_move_to_prewhere这个设置真实默认值是1(changed=0说明这是原始默认值,不是本文改过的),意味着ClickHouse的查询优化器会自动分析WHERE子句里的每个条件,把符合条件的(比如条件只依赖单一列、且这一列本身不算太重)自动提升成内部的PREWHERE步骤,完全不需要手写。
EXPLAIN actions=1 SELECT sum(length(payload)) FROM demo.pw2
WHERE flag=1 SETTINGS optimize_move_to_prewhere=0;
→ Aggregating
└──Filter ((WHERE + Change column names to column identifiers))
│ Filter column: flag = 1
└──ReadFromMergeTree (demo.pw2)
Output: payload.size, flag ← 真实变成了普通Filter,不再是Prewhere filter每一步都是本文上面用真实EXPLAIN actions=1跑出来的原始结果。
EXPLAIN actions=1system.settings(optimize_move_to_prewhere 默认值确认)