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

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

从高到低:

优先级 运算符
高 () 括号
↑ 算术:* / %,+ -
↑ 比较:= > < >= <= != <>,IN、LIKE、BETWEEN、IS
↑ NOT
↑ AND
低 OR

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


六、总结

要点 说明
优先级 NOT > AND > OR,AND 先于 OR 结合
主要风险 无括号的 OR 会让部分 AND 条件失效 → 数据越界 / 数据泄露
黄金法则 WHERE/ON 里 AND、OR 混用,一律给 OR 那组加括号
简化技巧 同字段多值用 IN;性能敏感的跨列 OR 考虑用 UNION 拆分
验证手段 用 EXPLAIN 看是否全表扫描;用少量数据核对结果集是否符合预期
相关推荐
天天喝旺仔3 小时前
MySQL 索引原理与慢查询优化实战:从 B+ 树到执行计划调优
数据库·sql·mysql·性能优化
m0_646429974 小时前
MySQL 初始化 SQL 中文乱码问题总结
数据库·sql·mysql
实战派K8S&DB4 小时前
TDSQL 核心模块与进程体系
运维·数据库·分布式·sql·mysql
Lost_the_wind4 小时前
MySQL 学习笔记三
笔记·学习·mysql
腾科IT教育5 小时前
Oracle OCP和MySQL OCP怎么选?方向对比指南
mysql·oracle·ocp·oracle ocp·ocp怎么选·mysql ocp
用户460381291946 小时前
别人都 commit 了,为什么我的 select 还是旧值?图解 MySQL MVCC
mysql
毕业设计7039 小时前
(免费领源码)django空气净化器销售系统09218- java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
python·scrapy·mysql·pycharm·django·flask·pandas
CJi0NG10 小时前
【自用】MySQL-事务
数据库·mysql
VX_bysjlw98510 小时前
数码设备销售网站设计与实现39138-计算机毕设原创(免费领源码+带部署教程)
java·vue.js·spring boot·mysql·tomcat·mybatis·idea
PHP实战开发录11 小时前
MySQL数字排序为什么乱
数据库·mysql·php