用一个先聚合再过滤的派生表查询,对比derived_condition_pushdown开启和关闭时的执行计划和耗时,看条件下推到底省下了什么。
如果不做任何优化,这类查询"应该"要先把全部数据聚合完,再从聚合结果里挑出需要的那一条。
代码SELECT * FROM ( SELECT customer_id, SUM(amount) AS total FROM orders1 GROUP BY customer_id ) AS agg WHERE agg.customer_id = 500; -- 30万条orders1,按5万个customer_id分组求和
关掉derived_merge,强制这个派生表物化,才能看清楚pushdown做了什么。
结果SET SESSION optimizer_switch='derived_merge=off,derived_condition_pushdown=on'; EXPLAIN SELECT ... -> Index lookup on agg using <auto_key0> (customer_id = 500) -> Materialize -> Filter: (orders1.customer_id = 500) ← 条件被下推到了这一层! -> Index scan on orders1 using idx_cust 耗时: 0.0004 s, 结果: (500, 3398)
关键在 Materialize 下面那一层:Filter: (orders1.customer_id = 500) 是在GROUP BY聚合之前就先筛出customer_id=500的原始订单行,再对这一小撮数据做聚合——条件被"下推"进了派生表内部,而不是等整个派生表都聚合完了再筛选。
同样的查询,只关掉这一个开关。
结果SET SESSION optimizer_switch='derived_merge=off,derived_condition_pushdown=off'; EXPLAIN SELECT ... -> Index lookup on agg using <auto_key0> (customer_id = 500) -> Materialize -> Group aggregate: sum(orders1.amount) ← 先对全部30万行做聚合 -> Index scan on orders1 using idx_cust ← 扫描全部30万行 耗时: 0.2554 s, 结果: (500, 3398) (结果依然正确,只是慢了)
derived_condition_pushdown 默认是开启的,这也是为什么大多数时候用户完全感知不到这个优化在发生,直到某天在一个更老版本或者手动关闭了这个开关的环境里,遇到一条"逻辑很简单但莫名其妙很慢"的查询。
每一步都是本文上面用EXPLAIN和计时跑出来的原始结果。
optimizer_switch derived_condition_pushdown:对比是否下推的执行计划与耗时