where 是逐行布尔判断,发生在 select 和 order by 之前,不支持别名引用;本质是行级过滤而非数学集合运算;空值、like 开头通配符、隐式类型转换是三大逻辑陷阱;性能取决于索引利用而非条件复杂度。

WHERE 条件本质是逐行逻辑判断
MySQL 的 WHERE 不是“提前过滤”或“智能索引跳过”,而是对 FROM 产出的每一行记录,执行一次布尔表达式求值:真 → 留下,假或 NULL → 舍弃。这个过程发生在 SELECT 列计算、别名(AS)和排序(ORDER BY)之前,所以你不能在 WHERE 里引用 SELECT 中定义的别名(比如 WHERE total > 100 报错,因为 total 还没生成)。
-
WHERE salary + bonus > 5000:每行都实时算一次加法,再比大小 -
WHERE name LIKE 'Li%':对每行name值做字符串匹配,不是查字典树 -
WHERE updated_at >= '2025-01-01':时间字段不走索引?那它就老老实实扫全表每行比时间
集合筛选 ≠ 数学集合运算,而是带语义的行级过滤
别被“集合”这个词误导——MySQL 没有把表当数学集合去交/并/差。所谓“筛选出满足条件的集合”,实际是:扫描原始数据集(可能是全表、索引覆盖扫描、或分区子集),对每条记录运行 WHERE 表达式,收集所有返回 TRUE 的行,拼成结果集。它不保证顺序、不自动去重(除非加 DISTINCT),也不关心行之间是否“属于同一逻辑组”。
- 没有隐含的
GROUP BY或唯一性约束 -
WHERE id IN (1,2,3)和WHERE id = 1 OR id = 2 OR id = 3语义等价,但执行计划可能不同(尤其有索引时) -
WHERE status != 'done'会漏掉status IS NULL的行——因为NULL != 'done'结果是NULL,不是TRUE
最容易踩的三个坑
这些不是语法错误,而是逻辑陷阱,线上查不到数据时八成栽在这儿:
-
空值陷阱:用
=、!=或>判断NULL全部失效,必须显式写IS NULL或IS NOT NULL -
LIKE 开头通配符:
WHERE name LIKE '%ing'无法使用 B+ 树索引的最左前缀,大概率触发全表扫描 -
隐式类型转换:比如
WHERE mobile = 13812345678(字段是VARCHAR),MySQL 会把字符串转数字再比,可能引发索引失效或意外匹配(如'13812345678abc'也被转成13812345678)
性能真相:WHERE 本身不慢,慢的是没走索引的逐行判断
WHERE 子句的执行成本,几乎完全取决于它能否利用索引快速定位(Index Seek),而不是靠 CPU 算得快。一旦变成全表扫描(type: ALL),哪怕条件再简单(WHERE 1=1),数据量大了照样卡。
- 建索引前先看
EXPLAIN SELECT ... WHERE ...的key和rows字段 - 复合索引要注意字段顺序:
INDEX(status, created_at)能加速WHERE status = 'active' AND created_at > '2025-01-01',但对WHERE created_at > '2025-01-01'无效 -
WHERE JSON_CONTAINS(info, '"admin"', '$.roles')这类函数条件,基本告别索引(除非建函数索引且 MySQL ≥ 8.0.13)










