当前位置: 首页 > news >正文

SQL中为什么不要使用1=1

最近看几个老项目的SQL条件中使用了1=1,想想自己也曾经这样写过,略有感触,特别拿出来说道说道。

编写SQL语句就像炒菜,每一种调料的使用都可能会影响菜品的最终味道,每一个SQL条件的加入也可能会影响查询的执行效率。那么 1=1 存在什么样的问题呢?为什么又会使用呢?

为什么会使用 1=1?

在动态构建SQL查询时,查询条件往往都是动态的,最终执行时可能会使用不同的条件。这时候,他们就会使用“1=1”作为一个始终为真的条件,让接下来的所有条件都可以方便地用“AND”连接起来,就像是搭积木的时候先放一个基座,其他的积木块就都可以在这个基座上叠加。

就像下边这样:

SELECT * FROM table WHERE 1=1
<if test="username != null">AND username = #{username}
</if>
<if test="age > 0">AND age = #{age}
</if>

这样就不用在增加每个条件之前先判断是否需要添加“AND”。

1=1 带来的问题

性能问题?

我们先来了解一下数据库查询优化器的工作原理。查询优化器就像是一个聪明的图书管理员,它知道如何最快地找到你需要的书籍。当你告诉它所需书籍的特征时,它会根据这些信息选择最快的检索路径。比如你要查询作者是“谭浩强”的书籍,它就选择先通过作者索引找到书籍索引,再通过书籍索引找到对应的书籍,而不是费力的把所有的书籍遍历一遍。

但是,如果我们告诉它一些无关紧要的信息,比如“我要一本书,它是一本书”,这并不会帮助管理员更快地找到书,反而可能会让他觉得困惑。一个带有“1=1”的查询可能会让数据库去检查每一条记录是否满足这个始终为真的条件,这就像是图书管理员不得不检查每一本书来确认它们都是书一样,显然是一种浪费。

你可能会说:数据库没有这么傻吧?

确实,这实际上可能不会产生问题,因为现代数据库的查询优化器已经非常智能,它们通常能够识别出像 1=1 这样的恒真条件,并在执行查询计划时优化掉它们。在许多情况下,即使查询中包含了1=1,数据库的性能也不会受到太大影响,优化器会在实际执行查询时将其忽略。

但是优化器并不是万能的。在某些复杂的查询场景中,即使是简单的 1=1 也可能对优化器的决策造成不必要的影响,比如导致全表扫描。

代码质量

另外从代码质量的角度,我们也需要避免在查询中包含 1=1,有以下几点考虑:

  1. 代码清晰性:即使数据库可以优化掉这样的条件,但对于阅读SQL代码的人来说,1=1可能会造成困惑。代码的可读性和清晰性非常重要,特别是在团队协作的环境中。
  2. 习惯养成:即使在当前的数据库系统中1=1不会带来性能问题,习惯了写不必要的代码可能会在其他情况下引入实际的性能问题。比如,更复杂的无用条件可能不会那么容易被优化掉。
  3. 跨数据库兼容性:不同的数据库管理系统(DBMS)可能有不同的优化器能力。一个系统可能轻松优化掉1=1,而另一个系统则可能不那么高效。编写不依赖于特定优化器行为的SQL语句是一个好习惯。

编写尽可能高效、清晰和准确的SQL语句,不仅有助于保持代码的质量,也让代码具有更好的可维护性和可扩展性。

替代 1=1 的更佳做法

现在开发者普遍使用ORM框架来操作数据库了,还在完全手写拼SQL的同学可能需要反思下了,这里给两个不同ORM框架下替代1=1的方法。

假设我们有一个用户信息表 user,并希望根据传入的参数动态地过滤用户。

首先是Mybatis

<!-- MyBatis映射文件片段 -->
<select id="selectUsersByConditions" parameterType="map" resultType="com.example.User">SELECT * FROM user<where><!-- 使用if标签动态添加条件 --><if test="username != null and username != ''">AND username = #{username}</if><if test="age > 0">AND age = #{age}</if><!-- 更多条件... --></where>
</select>

在 MyBatis 中,避免使用 1=1 的典型方法是利用动态SQL标签(如 <if>)来构建条件查询。<where> 标签会自动处理首条条件前的 AND 或 OR。当没有满足条件的 <if> 或其他条件标签时,<where> 标签内部的所有内容都会被忽略,从而不会生成多余的 AND 或 WHERE 子句。

再看看 Entity Framework 的方法:

var query = context.User.AsQueryable();
if (!string.IsNullOrEmpty(username))
{query = query.Where(b => b.UserName.Contains(username));
}
if (age>0)
{query = query.Where(b => b.Age = age);
}
var users = query.ToList();

这是一种函数式编程的写法,最终生成SQL时,框架会决定是否在条件前增加AND,而不需要人为的增加 1=1。

总结

“1=1”在SQL语句中可能看起来无害,但实际上它是一种不良的编程习惯,可能会导致性能下降。就像在做饭时不会无缘无故地多加调料一样,我们在编写SQL语句时也应该避免添加无意义的条件。

每一行代码都应该有它存在的理由,不要让人和数据库浪费时间在不必要的事情上。

http://www.lryc.cn/news/304493.html

相关文章:

  • python 几种常见的音频数据读取、保存方式
  • 关于msvcr120.dll丢失怎样修复的详细解决步骤方法分享,msvcr120.dll文件的相关内容
  • 简单几步通过DD工具把云服务器系统Linux改为windows
  • 使用 package.json 配置代理解决 React 项目中的跨域请求问题
  • 生成 Let‘s Encrypt 免费证书
  • int128的实现(基本完成)
  • 【linux】使用 acme.sh 实现了 acme 协议生成免费的SSL 证书
  • MACOS上面C/C++获取网卡索引,索引获取网卡接口名
  • 解决SSH远程登录开饭板出现密码错误问题
  • 什么时候用ref和reactive
  • Java实战:Spring Boot实现邮件发送服务
  • 重磅!MongoDB推出Atlas Stream Processing公共预览版
  • dell戴尔电脑灵越系列Inspiron 15 3520原厂Win11系统中文版/英文版
  • k8s(3)
  • Java多线程并发学习
  • Curfew e-Pass 管理系统存在Sql注入漏洞 附源代码
  • 记阿里云mysql丢表丢数据的实践记录
  • 自然语言转SQL的应用场景探索
  • Python学习笔记——PySide6设计GUI应用之UI与逻辑分离
  • 【智能家居入门2】(MQTT协议、微信小程序、STM32、ONENET云平台)
  • Java架构师之路九、设计模式:常见的设计模式,如单例模式、工厂模式、策略模式、桥接模式等
  • 【OpenAI官方课程】第三课:ChatGPT文本总结Summarizing
  • 跨越千年医学对话:用AI技术解锁中医古籍知识,构建能够精准问答的智能语言模型,成就专业级古籍解读助手(LLAMA)
  • 初识表及什么是数据表
  • 使用Docker部署DataX3.0+DataX-Web
  • 庖丁解牛-二叉树的遍历
  • 一文了解LM317T的引脚介绍、参数解读
  • 【2024.02.22】定时执行专家 V7.0 发布 - TimingExecutor V7.0 Release - 龙年春节重大更新版本
  • ☀️将大华摄像头画面接入Unity 【1】配置硬件和初始化摄像头
  • 直流电流电压变送器4-20mA 10V信号隔离转换模拟量精度变送器