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 NULLLIKE 开头通配符:
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) 真正决定 WHERE 效率的,从来不是条件写得多漂亮,而是数据库能不能“跳着读”,而不是“从头读到尾”。
