FROM 必须最先执行,因为 WHERE 依赖 FROM 提供的数据源;数据库先完成表读取、JOIN 和 CTE 展开生成虚拟表 VT1,再应用 WHERE 过滤,这是 SQL 标准定义的逻辑顺序,不可颠倒。

FROM 必须最先加载数据源,否则 WHERE 无数据可筛
因为数据库根本不知道要从哪张表里筛数据——WHERE 是对“已有行”的条件判断,而这些行只能来自 FROM 指定的表或连接结果。没有 FROM,WHERE 就像对着空气写过滤条件。
常见错误现象:在子查询或 CTE 中误以为 WHERE 能提前剪枝,结果发现全表扫描仍发生,就是因为优化器必须先完成 FROM 阶段的数据加载(哪怕后续 WHERE 条件极严)。
-
FROM阶段会实际读取物理表、执行JOIN、展开 CTE,生成第一个虚拟表(VT1) - 多表
JOIN时,即使书写顺序是FROM a JOIN b JOIN c,优化器也可能重排执行顺序,但逻辑起点仍是FROM列出的表集合 - 如果
FROM包含不可物化的视图或函数(如generate_series()),这部分开销必然在WHERE之前产生
WHERE 不能跳过 FROM 阶段的计算,这是语义决定的
SQL 是声明式语言,你写的是“要什么”,不是“怎么拿”。数据库必须先明确“数据在哪”(FROM),才能回答“哪些行符合”(WHERE)。这个顺序不是实现细节,而是 SQL 标准定义的逻辑处理流程。
使用场景:当你用 EXPLAIN 看执行计划时,第一行永远是 Table Scan 或 Index Scan,对应的就是 FROM 阶段;Filter 行才对应 WHERE 条件的实际应用位置。
-
WHERE中引用的列名,必须在FROM阶段已存在(比如不能引用SELECT里刚定义的别名) - 即使
WHERE条件能命中索引,数据库仍需先定位到该索引所属的表——这一步属于FROM的隐含动作 - 某些方言(如 MySQL 5.7+)允许在
WHERE中用子查询,但那个子查询本身也有自己的FROM,嵌套层级不改变主查询的执行顺序
容易踩的坑:误把书写顺序当执行顺序
人眼看到的是 SELECT ... FROM ... WHERE ...,但数据库引擎根本不按这个顺序干活。最典型的坑就是:
- 在
WHERE中写name_alias = 'foo',而name_alias是SELECT里用AS定义的——报错,因为WHERE执行时SELECT还没跑 - 以为加了
WHERE status = 'active'就能避免大表关联开销,结果JOIN仍基于全量主表进行,应优先考虑把过滤下推到FROM子查询中 - 在视图定义里写复杂
WHERE,却忘了视图只是存储SELECT语句,调用时仍要走完整FROM → WHERE流程
性能影响:FROM 阶段决定了 WHERE 的输入规模
FROM 阶段输出的数据量,直接决定 WHERE 的计算成本。一张千万行的表,和一张经 JOIN 后膨胀到五千万行的中间结果,同样一个 WHERE 条件,耗时可能差一个数量级。
参数差异:不同数据库对 FROM 阶段的优化能力不同。例如 PostgreSQL 会尝试将 WHERE 条件下推到 JOIN 内部(谓词下推),而某些旧版 MySQL 不支持,导致必须先完成笛卡尔积再过滤。
- 用
EXPLAIN ANALYZE对比两个查询:一个WHERE在主表,一个在JOIN后的临时结果上,看 Rows Removed by Filter 数值差异 - 对高频过滤字段,在
FROM涉及的每张表上建索引,比只在最终结果集上优化WHERE更有效 - 当
FROM包含多个大表LEFT JOIN,且WHERE只针对右表字段时,注意是否触发全左表扫描——此时应考虑改用子查询或INNER JOIN
WHERE 写得不够巧,而是 FROM 把不该带进来的数据全加载进来了。理解这一点,比背执行顺序更重要。

















