where子句须紧跟sql命令后,字符串值必须用单引号,null用is null判断,多条件需用括号明确优先级,in优于长or,between为闭区间,like慎用前导%;务必用explain验证索引使用。

WHERE 子句的基本写法和常见错误
MySQL 的 WHERE 子句必须紧跟在 SELECT、UPDATE 或 DELETE 语句之后,不能省略空格或换行导致语法断裂。最常踩的坑是把字符串值不加引号,比如写成 WHERE name = zhangsan —— 这会让 MySQL 把 zhangsan 当作列名或变量,直接报错 Unknown column 'zhangsan' in 'where clause'。
正确写法必须用单引号包裹字符串:WHERE name = 'zhangsan';数字可不加引号,但为统一风格和避免隐式转换问题,建议也加(尤其字段是 VARCHAR 但存了数字时)。
- NULL 值不能用
=判断,必须用IS NULL或IS NOT NULL - 空字符串
''和NULL是两回事,WHERE status = ''不会匹配到NULL记录 - 字段名含特殊字符或关键字时,要用反引号:例如
WHERE `order` = 1
多条件组合:AND、OR、NOT 和括号优先级
多个条件默认按从左到右、AND 优先于 OR 执行,但容易误判逻辑。比如 WHERE type = 'user' OR type = 'admin' AND status = 1 实际等价于 WHERE type = 'user' OR (type = 'admin' AND status = 1),而不是你想要的「是 user 或 admin 且 status=1」。
解决办法只有显式加括号:WHERE (type = 'user' OR type = 'admin') AND status = 1。另外注意 NOT 的作用范围很小,NOT age > 18 等价于 age ,但 <code>NOT (age > 18 AND city = 'bj') 才是否定整个组合。
-
AND条件越多,结果集越小,索引利用可能越好(取决于是否覆盖) -
OR容易让 MySQL 放弃使用索引,尤其是跨字段 OR(如WHERE a=1 OR b=2),考虑改写为UNION - 用
IN替代长串OR更清晰:例如WHERE status IN (0, 1, 2)
BETWEEN、IN、LIKE 和 NULL 安全比较
BETWEEN 是闭区间,WHERE id BETWEEN 10 AND 20 等价于 WHERE id >= 10 AND id ,别误以为是开区间。它对日期也适用:<code>created_at BETWEEN '2024-01-01' AND '2024-01-31'。
IN 要小心空集合和 NULL:如果子查询返回 NULL,比如 WHERE id IN (SELECT uid FROM logs WHERE ...),而子查询结果含 NULL,整条 IN 判断会变成 UNKNOWN,该行被过滤掉 —— 这不是 bug,是 SQL 三值逻辑决定的。
-
LIKE中%匹配任意长度(含零),_匹配单个字符;前导 %(如LIKE '%abc')无法使用普通 B-tree 索引 - 想安全地查 NULL 或非 NULL,坚持用
IS NULL/IS NOT NULL,别用= NULL(永远返回 false) -
是 NULL 安全等于操作符,a b在 a 和 b 都为 NULL 时返回 1,但仅限于比较,不能用于索引优化
WHERE 和索引失效的典型场景
写了 WHERE 不代表就走索引。函数操作字段是最常见原因:比如 WHERE YEAR(created_at) = 2024 或 WHERE UPPER(name) = 'ABC',会导致全表扫描。MySQL 无法用索引去“反推”函数结果。
另一个高发点是隐式类型转换:WHERE phone = 13812345678,如果 phone 是 VARCHAR 类型,MySQL 会把右侧数字转为字符串再比,但某些版本下仍可能放弃索引;更稳妥写法是 WHERE phone = '13812345678'。
- 复合索引要遵循最左前缀原则:索引
(a,b,c)可用于WHERE a=1、WHERE a=1 AND b>2,但不能用于WHERE b=2单独出现 -
!=或通常不走索引(除非统计信息极偏斜),尽量改用范围或IN拆解 - 用
EXPLAIN看type是否为range/ref,而不是ALL,才能确认 WHERE 真正用了索引
EXPLAIN 一眼,看 key 和 rows 是多少。









