UNION ALL视图拦不住WHERE条件,因优化器不跨分支下推谓词,每个子查询需独立加WHERE、避免GROUP BY/DISTINCT/SELECT*、确保类型对齐且索引可用。

UNION ALL视图为什么拦不住WHERE条件?
因为优化器默认不跨分支做全局谓词下推——它把每个SELECT子查询当作独立单元处理,外层WHERE不会自动拆解并注入到每个分支里。你写(SELECT id FROM t1) UNION ALL (SELECT id FROM t2) WHERE id = 100,数据库大概率先执行两个全表扫描,再合并后过滤,而不是让每个子查询直接走id = 100索引。
哪些结构会彻底关闭谓词下推通道?
不是UNION ALL本身的问题,而是它常和以下结构共存,触发优化器放弃下推:
-
GROUP BY或DISTINCT:一旦子查询含聚合,中间结果必须物化,外层条件无法穿透 -
SELECT *+ 大字段(如TEXT、JSON):破坏列的可下推性,优化器不敢假设类型安全 - 嵌套三层以上视图(A → B → C):估算偏差大,尤其某层含
LIMIT或ORDER BY时,驱动表选择错乱 - 列类型不一致(如一边
VARCHAR(50),一边VARCHAR(255)):隐式转换导致索引失效,下推失去意义
怎么验证谓词到底有没有下推?
看执行计划最底层的扫描节点是否已带过滤条件:
- MySQL:查
EXPLAIN输出,type为ref或range,且Extra不含Using temporary - PostgreSQL:用
EXPLAIN (ANALYZE, BUFFERS),确认Filter出现在Seq Scan或Index Scan节点内,而非顶层Result或Materialize - SQL Server:开
SET STATISTICS XML ON,找Table Scan或Index Seek节点下的Predicate,不是Filter操作符
绕过限制的实操手段有哪些?
没有银弹,但有几条硬约束必须满足:
- 每个子查询必须独立可优化:对每个
SELECT单独跑EXPLAIN,确保能走索引 - 把外层
WHERE条件手动复制进每个子查询:(SELECT id FROM t1 WHERE status = 'active') UNION ALL (SELECT id FROM t2 WHERE status = 'pending'),别指望优化器帮你拆 - 禁用视图定义里的
ORDER BY(MySQL非法;PG/SQL Server中它只影响视图输出顺序,不加速查询) - 高频场景考虑替代方案:用
CTE重写+ROW_NUMBER()控制截断,或定时物化到带索引的汇总表
真正容易被忽略的是类型对齐——哪怕只是VARCHAR长度差一位,都可能让整个下推链路失效,而错误信息里往往只报“column type mismatch”,不会提示性能后果。










