MySQL中的 where 1=1会不会影响性能?看完官方文档就悟了!

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 本文探讨了在Mybatis中使用`where 1=1`进行动态SQL拼接是否会影响性能。通过MySQL官方资料和实际测试表明,`where 1=1`在MySQL 5.7及以上版本中会被优化器优化,因此对性能影响不大。文中详细对比了`where 1=1`与`<where>`标签的使用方法,并建议根据MySQL版本和团队需求选择合适的方式。最后,推荐查找官方资料以确保技术路线正确。

你好,我是猿java。

在日常业务开发中,会通过使用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();

mysql-version.png

场景:基于一张拥有 100多万条数据的user表,根据name进行查询,

查看表结构和表的总数据,如下图:
mysql-describle-table.png

mysql-count-user.png

下面,通过执行两条 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';

mysql-where-1-1-compare.png

对比两条 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;

img.png

将上述示例的 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的版本影响。
sql-model.png

查阅了 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

信息补充: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

学习交流

如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注:猿java,持续输出硬核文章。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
8天前
|
存储 关系型数据库 MySQL
提高MySQL查询性能的方法有很多
提高MySQL查询性能的方法有很多
52 6
|
8天前
|
存储 关系型数据库 MySQL
提高MySQL的查询性能
提高MySQL的查询性能
29 4
|
1月前
|
SQL 关系型数据库 MySQL
MySQL 8.0:filesort 性能退化的问题分析
用户将 RDS MySQL 实例从 5.6 升级到 8.0 后,发现相同 SQL 的执行时间增长了十几倍。本文就该问题逐步展开排查,并最终定位根因。
|
1月前
|
关系型数据库 MySQL
mysql 官网文档
mysql官网使用指南
mysql 官网文档
|
14天前
|
存储 关系型数据库 MySQL
MySQL索引失效及避免策略:优化查询性能的关键
MySQL索引失效及避免策略:优化查询性能的关键
95 3
|
14天前
|
缓存 关系型数据库 MySQL
MySQL数据库优化:提升性能和扩展性的关键技巧
MySQL数据库优化:提升性能和扩展性的关键技巧
39 2
|
5天前
|
存储 关系型数据库 MySQL
四种数据库对比MySQL、PostgreSQL、ClickHouse、MongoDB——特点、性能、扩展性、安全性、适用场景
四种数据库对比 MySQL、PostgreSQL、ClickHouse、MongoDB——特点、性能、扩展性、安全性、适用场景
|
14天前
|
监控 关系型数据库 MySQL
如何优化MySQL数据库的索引以提升性能?
如何优化MySQL数据库的索引以提升性能?
30 0
|
2月前
|
SQL 关系型数据库 MySQL
【MySQL 慢查询秘籍】慢SQL无处遁形!实战指南:一步步教你揪出数据库性能杀手!
【8月更文挑战第24天】本文以教程形式深入探讨了MySQL慢SQL查询的分析与优化方法。首先介绍了如何配置MySQL以记录执行时间过长的SQL语句。接着,利用内置工具`mysqlslowlog`及第三方工具`pt-query-digest`对慢查询日志进行了详细分析。通过一个具体示例展示了可能导致性能瓶颈的查询,并提出了相应的优化策略,包括添加索引、缩小查询范围、使用`EXPLAIN`分析执行计划等。掌握这些技巧对于提升MySQL数据库性能具有重要意义。
88 1
|
2月前
|
缓存 关系型数据库 MySQL
在Linux中,如何优化MySQL性能,包括索引优化和查询分析?
在Linux中,如何优化MySQL性能,包括索引优化和查询分析?

热门文章

最新文章