SQL 里的 AND / OR 优先级陷阱:一个括号引发的“数据越界“

SQL 里的 AND / OR 优先级陷阱:一个括号引发的"数据越界"

一、背景:给 WHERE 加了个 OR,差点全表数据都出来了

在一次查询接口的调整中,原本的 WHERE 是这样:

sql 复制代码
where w.warehouse_type = 3
  and st.member_id = xxx

需求要额外支持"xxx仓"(warehouse_business_type = 2),有人顺手改成:

sql 复制代码
where w.warehouse_type = 3 or w.warehouse_business_type = 2
  and st.member_id = xxx

看起来只是"多查一种仓库类型",实际却是个严重 bug:member_id = xxx 这个限制对一部分数据失效了,会把别的客户、别的时间的数据也查出来------典型的"数据越界"。

根因就是 AND 和 OR 的运算优先级


注:

博客:

https://blog.csdn.net/badao_liumang_qizhi

二、核心概念:AND 优先级高于 OR

SQL 里逻辑运算符有明确的优先级顺序(从高到低):

复制代码
NOT  >  AND  >  OR

也就是说,AND先于 OR 结合。当一个 WHERE 里同时有 AND 和 OR 又没加括号时,数据库会先把 AND 两边"绑在一起",再和 OR 组合。

回到那句 SQL,数据库实际是这样理解的(等价于自动加了括号):

sql 复制代码
where (w.warehouse_type = 3)
   OR (w.warehouse_business_type = 2 AND st.member_id = xxxx)

拆开看这两个分支:

  • 分支1:w.warehouse_type = 3 ------ 完全不带 member_id 条件,只要是 type=3 的仓,所有客户、所有时间的数据都会被选出来
  • 分支2:w.warehouse_business_type = 2 AND st.member_id = 226887 ------ 这个才带了客户限制

结果:本该"限定 xxx这个客户"的查询,在 type=3 分支上彻底失控。这在生产上意味着数据泄露 + 慢查询(全表扫描)

正确写法:用括号明确意图

sql 复制代码
where (w.warehouse_type = 3 or w.warehouse_business_type = 2)
  and st.member_id = xxx

加了括号后,两个仓库类型的 OR 被"锁"在一起,整体再和 member_id = xxx 做 AND。这样无论哪种仓库类型,都必须满足 member_id = xxxx,意图清晰、结果正确。

一句话:只要 WHERE 里 AND 和 OR 混用,就应该用括号把 OR 显式括起来,不要依赖默认优先级。


三、通用示例场景

示例1:查询商品------"电子类 或 图书类,且库存大于 0"

sql 复制代码
-- 错误:没加括号
SELECT * FROM product
WHERE category = '电子' OR category = '图书' AND stock > 0;

-- 实际被理解成:
-- category='电子'  (不管库存)
-- OR (category='图书' AND stock>0)
-- 结果:库存为 0 的电子产品也被查出来了
-- 正确:加括号
SELECT * FROM product
WHERE (category = '电子' OR category = '图书') AND stock > 0;

示例2:用户筛选------"VIP 或 高消费用户,且账号未封禁"

sql 复制代码
-- 错误
SELECT * FROM users
WHERE is_vip = 1 OR total_amount > 10000 AND status = 'active';
-- 被理解为:is_vip=1(含被封禁的VIP)OR (高消费 AND 未封禁)
-- 后果:被封禁的 VIP 也被查出来

-- 正确
SELECT * FROM users
WHERE (is_vip = 1 OR total_amount > 10000) AND status = 'active';

示例3:日志查询------"错误 或 警告级别,且属于今天"

sql 复制代码
-- 正确写法
SELECT * FROM log
WHERE (level = 'ERROR' OR level = 'WARN')
  AND create_time >= '2026-09-18 00:00:00';

如果不加括号,level='ERROR' 会脱离时间限制,把历史所有 ERROR 日志都拉出来。

示例4:用 IN 替代多个 OR,更清晰也更安全

上面"多个 OR 判断同一个字段"的场景,用 IN 会更简洁,还天然避免优先级问题:

sql 复制代码
-- 用 IN 代替 category='电子' OR category='图书'
SELECT * FROM product
WHERE category IN ('电子', '图书') AND stock > 0;

IN 本身是一个整体条件,和后面的 AND 组合时不存在优先级歧义。能用 IN 就别堆 OR。


四、容易踩的坑

坑1:OR 混进一堆 AND 里,最隐蔽

WHERE 条件多的时候,一个 OR 夹在中间最容易出事:

sql 复制代码
-- 危险:a、b、d 都是限制条件,中间冒出一个 or c
WHERE a = 1 AND b = 2 OR c = 3 AND d = 4;
-- 实际 = (a=1 AND b=2) OR (c=3 AND d=4)

条件越多,默认优先级带来的结果越难一眼看出。规则:只要有 OR,就给 OR 那组加括号。

坑2:OR 让索引失效、引发全表扫描

优先级错误还常常伴随性能问题。像 WHERE type=3 OR business_type=2

  • 如果两个列各有索引,MySQL 有时能用 index merge,但跨列 OR 经常用不上索引
  • 更糟的是优先级错误让某个分支丢失了主过滤条件(如 member_id、时间),直接退化成全表扫描

优化方向:

  • 同字段多值用 IN
  • 不同字段的 OR,若性能敏感,考虑用 UNION 拆成两个能各自走索引的查询
sql 复制代码
SELECT ... WHERE warehouse_type = 3 AND member_id = 226887
UNION
SELECT ... WHERE warehouse_business_type = 2 AND member_id = 226887;

坑3:OR 与 NOT 一起用

NOT 优先级最高,NOT a = 1 OR b = 2 等于 (NOT a=1) OR b=2,不是 NOT (a=1 OR b=2)。同样靠括号消除歧义。

坑4:JOIN 的 ON 条件里也有同样问题

不只是 WHERE,JOIN 的 ON 子句里 AND/OR 混用也遵循同样优先级,一样要加括号:

sql 复制代码
LEFT JOIN t2 ON (t1.a = t2.a OR t1.b = t2.b) AND t2.status = 1

五、运算符优先级速查(常用部分)

从高到低:

优先级 运算符
() 括号
算术:* / %+ -
比较:= > < >= <= != <>INLIKEBETWEENIS
NOT
AND
OR

记住核心一条:AND 比 OR 先算。其余细节记不住没关系,加括号永远是对的。


六、总结

要点 说明
优先级 NOT > AND > OR,AND 先于 OR 结合
主要风险 无括号的 OR 会让部分 AND 条件失效 → 数据越界 / 数据泄露
黄金法则 WHERE/ON 里 AND、OR 混用,一律给 OR 那组加括号
简化技巧 同字段多值用 IN;性能敏感的跨列 OR 考虑用 UNION 拆分
验证手段 用 EXPLAIN 看是否全表扫描;用少量数据核对结果集是否符合预期
相关推荐
爱奥尼欧4 小时前
【MySQL】建库就是建目录?字符集校验规则、备份恢复与alter改表实操
mysql
大虾别跑4 小时前
mysql5.7升级
mysql
geovindu4 小时前
sql: Transaction & Concurrency Patterns using mysql 9.0
mysql·数据库开发·数据库架构
敲代码的瓦龙5 小时前
Jetpack?DataBinding!!!
android·java·开发语言·mysql·android-studio
想念是会呼吸的鱼5 小时前
MySQL 常用语法整理
sql·mysql
不正经的码狗5 小时前
MySQL 免安装教程|安装不报错
mysql
旋生万物5 小时前
MySQL 死锁总复发?用螺旋事务相位互逆法定位加锁顺序(附 Python 诊断脚本)
mysql·大模型·innodb·螺旋生成论·螺旋相位
星光开发者7 小时前
基于Spring Boot的充电桩管理系统的设计与实现-计算机毕设【课程设计】57105
vue.js·spring boot·vscode·mysql·django·php·express
imDwAaY7 小时前
MySQL MVCC 详解:原理、版本链、Read View 与可见性判断
数据库·sql·mysql