MySQL的 where 1=1会不会影响性能?看完官方文档就悟了!
wptr33 2025-01-10 17:38 25 浏览
在日常业务开发中,会通过使用where 1=1来简化动态 SQL语句的拼接,有人说where 1=1会影响性能,也有人说不会,到底会不会影响性能?本文将从 MySQL的官方资料来进行分析。
动态拼接 SQL的方法
在 Mybatis中,动态拼接 SQL最常用的两种方式:使用 where 1=1 和 使用<where>标签。
使用where 1=1
使用过 iBATIS的小伙伴应该都知道:在 iBATIS中没有<where>标签,动态 SQL的处理相对较为原始和复杂,因此使用where 1=1这种写法的用户很大一部分是还在使用 iBATIS 或者是从 iBATIS过度到 Mybatis。
如下示例,通过where 1=1来动态拼接有效的 if语句:
<select id="" parameterType = "">
SELECT * FROM user
WHERE 1=1
<if test="name != null and name != ''">
AND name = #{name}
</if>
<if test="age != null ">
AND age = #{age }
</if>
</select>
使用<where>标签
Mybatis提供了<where>标签,<where>标签只有在至少一个 if条件有值的情况下才去生成 where子句,若 AND或 OR前没有有效语句,where元素会将它们去除,也就是说,如果 Mybatis通过<where>标签动态生成的语句为where AND name = '111',最终会被优化为where name = '111'。
<where>标签使用示例如下:
<select id="" parameterType = "">
SELECT * FROM user
<where>
<if test="name != null and name != ''">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
<where>标签是在 MyBatis中引入的,所以,很多一开始就使用 MyBatis的用户对这个标签使用的比较多。
性能影响
where 1=1到底会不会影响性能?我们可以先看一个具体的例子:
说明:示例基于 MySQL 8.0.30
可以使用如下指令查看 MySQL版本:
SELECT VERSION();
场景:基于一张拥有 100多万条数据的user表,根据name进行查询,
查看表结构和表的总数据,如下图:
下面,通过执行两条 SQL查询语句(一条带有 1=1):
select * from user where name = 'name-96d1b3ce-1a24-4d47-b686-6f9c6940f5f6';
select * from user where 1=1 and name = 'name-f692472e-40de-4053-9498-54b9800e9fb1';
对比两条 SQL执行的结果,可以发现它们消耗的时间几乎相同,因此,看起来where 1=1对整体的性能似乎并不影响。
为了排除一次查询不具有代表性,我们分别对两条 SQL语句查询 100遍,然后计算平均值:
SET PROFILING = 1;
DO SLEEP(0.001); -- 确保每次查询之间有足够时间间隔
SET @count = 0;
WHILE @count < 100 DO
select * from user where name = 'name-96d1b3ce-1a24-4d47-b686-6f9c6940f5f6';
-- or
select * from user where 1=1 and name = 'name-f692472e-40de-4053-9498-54b9800e9fb1';
SET @count = @count + 1;
END WHILE;
SHOW PROFILES;
两条 SQL分别执行 100次后,最终也发现它们的平均值几乎相同,因此,上述示例似乎证明了 where 1=1 对整体的性能并没有不影响。
为什么没有影响?是不是 MySQL对 1=1进行了优化?
为了证明猜想,我们借助show warnings命令来查看信息,在 MySQL中,show warnings命令用于显示最近执行的 SQL语句产生的警告、错误或通知信息。它可以帮助我们了解语句执行过程中的问题。如下示例:
explain select * from user where 1=1 and name = 'name-f692472e-40de-4053-9498-54b9800e9fb1';
show warnings;
将上述示例的 warnings信息摘出来如下:
/* select#1 */ select `yuanjava`.`user`.`id` AS `id`,
`yuanjava`.`user`.`name` AS `name`,
`yuanjava`.`user`.`age` AS `age`,
`yuanjava`.`user`.`sex` AS `sex`,
`yuanjava`.`user`.`created_at` AS `created_at`
from `yuanjava`.`user`
where (`yuanjava`.`user`.`name` = 'name-f692472e-40de-4053-9498-54b9800e9fb1')
从 warnings信息可以看出:1=1已经被查询优化器优化掉,因此,对整体的性能影响并不大。
那么,有没有 MySQL的官方资料可以佐证 where 1=1确实被优化了?
答案:有!MySQL有一种 Constant-Folding Optimization(常量折叠优化)的功能。
Constant-Folding Optimization
MySQL的优化器具有一项称为 Constant-Folding Optimization(常量折叠优化)的功能,可以从查询中消除重言式表达式。Constant-Folding Optimization 是一种编译器的优化技术,用于优化编译时计算表达式的常量部分,从而减少运行时的计算量,换句话说:Constant-Folding Optimization 是发生在编译期,而不是引擎执行期间。
对于上述表达的"重言式表达式"又是什么呢?
重言式
重言式(Tautology )又称为永真式,它的汉语拼音为:[Chóng yán shì],是逻辑学的名词。命题公式中有一类重言式,如果一个公式,对于它的任一解释下其真值都为真,就称为重言式(永真式)。
其实,重言式在计算机领域也具有重要应用,比如"重言式表达式"(Tautological expression),它指的是那些总是为真的表达式或逻辑条件。
在 SQL查询中,重言式表达式是指无论在什么情况下,结果永远为真,它们通常会被优化器识别并优化掉,以提高查询效率。例如,如果 where中包含 1=1 或 A=A 这种重言式表达式,它们就会被优化器移除,因为对查询结果没有实际影响。如下两个示例:
SELECT * from user where 1=1 and name = 'xxx';
-- 被优化成
SELECT * from user where name = 'xxx';
SELECT id, name, salary * (1 + 0.05 * 2) AS real_salary FROM employees;
-- 优化成(1 + 0.05 * 2 被优化成 1.1)
SELECT id, name, salary * 1.1 AS real_salary FROM employees;
另外,通过下面 MySQL架构示意图可以看出:优化器是属于 MySQL的 Server层,因此,Constant-Folding Optimization功能支持受 MySQL Server的版本影响。
查阅了 MySQL的官方资料,Constant-Folding Optimization 从 MySQL5.7版本开始引入,至于 MySQL5.7以前的版本是否具备这个功能,还有待考证。
如何选择?
where 1=1 和 <where> 标签 两种方案,该如何选择?
- 如果 MySQL Server版本大于等于 5.7,两个随便选,或者根据团队的要求来选;
- 如果 MySQL Server版本小于 5.7,假如使用的是 MyBatis,建议使用<where> 标签,如果使用的还是比较老的 iBATIS,只能使用where 1=1;
- 如果 MySQL Server版本小于 5.7,建议升升级
信息补充:2009年5月,iBATIS从 2.0版本开始更名为 MyBatis, 标签最早出现在MyBatis 3.2.0版本中
总结
where 1=1和<where> 标签到底会不会影响性能,这个问题在网上已经出现了很多次,今天还是想从官方文档来进行说明。本文通过 MySQL的官方资料,加上百万数据的表进行真实测试,得出下面的结论:
- 如果 MySQL Server版本大于等于 5.7,两个随便选,或者根据团队的要求来选;
- 如果 MySQL Server版本小于 5.7,假如使用的是 MyBatis,建议使用<where> 标签,如果使用的还是比较老的 iBATIS,只能使用where 1=1;
最后,遇到问题,建议首先查找官方的一手资料,这样才能帮助自己在一条正确的技术道路上成长!
参考资料
MySQL8.0 Constant-Folding Optimization
MySQL5.7 WHERE Clause Optimization
What’s New in MySQL 5.7
学习交流
最后,把我的座右铭送给你:投资自己才是最大的财富。 如果你觉得本文章对你有帮助,点赞,收藏不迷路,关注公众号:我不是架构师,持续为你输出更多的硬核文章和面试经。
相关推荐
- redis的八种使用场景
-
前言:redis是我们工作开发中,经常要打交道的,下面对redis的使用场景做总结介绍也是对redis举报的功能做梳理。缓存Redis最常见的用途是作为缓存,用于加速应用程序的响应速度。...
- 基于Redis的3种分布式ID生成策略
-
在分布式系统设计中,全局唯一ID是一个基础而关键的组件。随着业务规模扩大和系统架构向微服务演进,传统的单机自增ID已无法满足需求。高并发、高可用的分布式ID生成方案成为构建可靠分布式系统的必要条件。R...
- 基于OpenWrt系统路由器的模式切换与网页设计
-
摘要:目前商用WiFi路由器已应用到多个领域,商家通过给用户提供一个稳定免费WiFi热点达到吸引客户、提升服务的目标。传统路由器自带的Luci界面提供了工厂模式的Web界面,用户可通过该界面配置路...
- 这篇文章教你看明白 nginx-ingress 控制器
-
主机nginx一般nginx做主机反向代理(网关)有以下配置...
- 如何用redis实现注册中心
-
一句话总结使用Redis实现注册中心:服务注册...
- 爱可可老师24小时热门分享(2020.5.10)
-
No1.看自己以前写的代码是种什么体验?No2.DooM-chip!国外网友SylvainLefebvre自制的无CPU、无操作码、无指令计数器...No3.我认为CS学位可以更好,如...
- Apportable:拯救程序员,IOS一秒变安卓
-
摘要:还在为了跨平台使用cocos2d-x吗,拯救objc程序员的奇葩来了,ApportableSDK:FreeAndroidsupportforcocos2d-iPhone。App...
- JAVA实现超买超卖方案汇总,那个最适合你,一篇文章彻底讲透
-
以下是几种Java实现超买超卖问题的核心解决方案及代码示例,针对高并发场景下的库存扣减问题:方案一:Redis原子操作+Lua脚本(推荐)//使用Redis+Lua保证原子性publicbo...
- 3月26日更新 快速施法自动施法可独立设置
-
2016年3月26日DOTA2有一个79.6MB的更新主要是针对自动施法和快速施法的调整本来内容不多不少朋友都有自动施法和快速施法的困扰英文更新日志一些视觉BUG修复就不翻译了主要翻译自动施...
- Redis 是如何提供服务的
-
在刚刚接触Redis的时候,最想要知道的是一个’setnameJhon’命令到达Redis服务器的时候,它是如何返回’OK’的?里面命令处理的流程如何,具体细节怎么样?你一定有问过自己...
- lua _G、_VERSION使用
-
到这里我们已经把lua基础库中的函数介绍完了,除了函数外基础库中还有两个常量,一个是_G,另一个是_VERSION。_G是基础库本身,指向自己,这个变量很有意思,可以无限引用自己,最后得到的还是自己,...
- China's top diplomat to chair third China-Pacific Island countries foreign ministers' meeting
-
BEIJING,May21(Xinhua)--ChineseForeignMinisterWangYi,alsoamemberofthePoliticalBureau...
- 移动工作交流工具Lua推出Insights数据分析产品
-
Lua是一个适用于各种职业人士的移动交流平台,它在今天推出了一项叫做Insights的全新功能。Insights是一个数据平台,客户可以在上面实时看到员工之间的交流情况,并分析这些情况对公司发展的影响...
- Redis 7新武器:用Redis Stack实现向量搜索的极限压测
-
当传统关系型数据库还在为向量相似度搜索的性能挣扎时,Redis7的RedisStack...
- Nginx/OpenResty详解,Nginx Lua编程,重定向与内部子请求
-
重定向与内部子请求Nginx的rewrite指令不仅可以在Nginx内部的server、location之间进行跳转,还可以进行外部链接的重定向。通过ngx_lua模块的Lua函数除了能实现Nginx...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
面试官:git pull是哪两个指令的组合?
-
git 执行pull错误如何撤销 git pull fail
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)