真实用sleepEachRow这种有明显耗时的表达式验证WITH子句和手写重复子查询是否真的只执行一次,找到真相是公共子表达式消除而非WITH语法本身。
代码-- 用WITH,引用3次 WITH (SELECT sleepEachRow(0.5) FROM numbers(1)) AS side SELECT side, side, side FROM numbers(1); -- 不用WITH,同样的子查询原样抄写3遍 SELECT (SELECT sleepEachRow(0.5) FROM numbers(1)), (SELECT sleepEachRow(0.5) FROM numbers(1)), (SELECT sleepEachRow(0.5) FROM numbers(1));
WITH引用3次(相同sleepEachRow(0.5)): 真实耗时 503ms 不用WITH,原样抄写3遍(相同的0.5): 真实耗时 507ms ← 意外:也只有约500ms,不是1500ms!
如果子查询真的每次出现都被真实执行一次,"抄写3遍0.5秒的sleep"应该真实耗时接近1.5秒,但实测只有507毫秒——跟用WITH的503毫秒几乎没有差别。这说明决定子查询是否真的重复执行的,不是"有没有用WITH关键字"。
3个字面不同的sleep(0.5)/(0.6)/(0.7),不用WITH: → 真实耗时 1823ms ≈ 0.5+0.6+0.7=1.8秒 ← 真实按3次独立执行处理 2个字面完全相同的sleep(0.5)/(0.5),出现在WHERE子句里: → 真实耗时 516ms ≈ 只有1次的耗时,不是2次的1秒
每一步都是本文上面用真实sleepEachRow跑出来的原始耗时。
sleepEachRow() 的耗时反推子查询求值次数