视图中LEFT JOIN不会被优化器跳过,必须显式加WHERE过滤并建索引,否则主查询将陷入NLJ陷阱。MySQL不支持基于SELECT列反向裁剪视图JOIN,视图定义中的LEFT JOIN必执行,未过滤的大右表会导致扫描行数乘积级增长,嵌套视图更会指数级放大性能风险。

视图里加了没用的 LEFT JOIN,不是“多连一张表而已”,而是直接把主查询拖进嵌套循环(NLJ)陷阱——哪怕右表只有一行,只要没索引或没过滤,MySQL 就得为左表每一行都扫一遍右表。
LEFT JOIN 在视图里不会被优化器跳过
很多人以为“这个 JOIN 只在视图里,我主查询没选它的字段,数据库应该自动忽略”。错。MySQL 不会基于 SELECT 列反向裁剪视图中的 JOIN;只要视图定义里写了 LEFT JOIN t2 ON ...,执行时就一定会走完这个关联逻辑,哪怕你最后只 SELECT id, name,完全不碰 t2 的任何列。
- 视图不是函数,没有“懒加载”机制;它是预定义的查询逻辑,解析后直接展开进主 SQL
- EXPLAIN 里能看到 t2 表出现在执行计划中,
rows列数值飙升,Extra出现Using temporary; Using filesort - 如果 t2 是大表且没索引,
Handler_read_rnd_next会暴涨,意味着每行左表数据都在反复全表扫描 t2
视图中 LEFT JOIN 缺少 WHERE 过滤,等于放大右表数据集
硬写 LEFT JOIN logistics l ON o.order_id = l.order_id 而不在视图定义里加 WHERE l.status IN ('shipped', 'delivered'),等于把整张物流表都拉进来参与关联。即使主查询只查最近 7 天订单,视图仍会先关联全部历史物流记录,再由主查询的 WHERE 去筛——但这时中间结果早已膨胀。
- 过滤条件写在主查询
WHERE里,对视图内的LEFT JOIN无提前裁剪作用 - 必须把业务有效范围(如状态、时间范围、租户 ID)显式写进视图的
WHERE子句,才能缩小右表参与关联的数据量 - 视图定义中没
WHERE,等价于WHERE 1=1,优化器无法估计基数,极易选错连接算法
多个视图嵌套时,LEFT JOIN 的代价会指数级叠加
比如 v_order_detail 视图里有 LEFT JOIN users,v_order_summary 又基于它再 LEFT JOIN addresses,那每次查 v_order_summary,users 和 addresses 都会被完整关联两次:一次在子视图里,一次在父视图展开后。
- 嵌套视图让执行计划变得不可预测,EXPLAIN 看到的往往是“黑盒”,
rows严重低估或高估 - 每层
LEFT JOIN都可能触发一次 NLJ,三层嵌套下,扫描行数可能是左表 × 右表1 × 右表2 × 右表3 - SQL Server 对远程视图更敏感——它硬编码基数为 10000,叠加嵌套后几乎必然选错哈希/嵌套循环策略
真正要警惕的不是“用了 LEFT JOIN”,而是“没想清楚这张表是不是真要此刻关联”。视图里的每个 LEFT JOIN 都该回答三个问题:它被哪些下游查询真正用到?能否用 WHERE 先筛掉 90% 的右表数据?有没有索引让 ON 条件能走 Index Seek?漏掉任意一条,就是给主查询埋雷。

















