首页 > 数据库 >SQL中为什么不要使用1=1?

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

时间:2024-02-20 23:44:24浏览次数:31  
标签:username 为什么 不要 数据库 条件 查询 SQL 优化

最近看几个老项目的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. 代码清晰性:即使数据库可以优化掉这样的条件,但对于阅读SQL代码的人来说,1=1可能会造成困惑。代码的可读性和清晰性非常重要,特别是在团队协作的环境中。
  2. 习惯养成:即使在当前的数据库系统中1=1不会带来性能问题,习惯了写不必要的代码可能会在其他情况下引入实际的性能问题。比如,更复杂的无用条件可能不会那么容易被优化掉。
  3. 优化器的限制:虽然现代优化器很强大,但它们并不是万能的。在某些复杂的查询场景中,即使是简单的 1=1 也可能对优化器的决策造成不必要的影响,比如索引的使用。
  4. 跨数据库兼容性:不同的数据库管理系统(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 中,避免使用 WHERE 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语句时也应该避免添加无意义的条件。

每一行代码都应该有它存在的理由,不要让你的数据库像一个困惑的图书管理员,浪费时间在不必要的事情上。

标签:username,为什么,不要,数据库,条件,查询,SQL,优化
From: https://www.cnblogs.com/bossma/p/18024285

相关文章

  • MySQL
    MySQL创建和删除资料库CREATEDATABASE`sql_tutorial`;#创建资料库SHOWDATABASES;#展示所有资料库DROPDATABASE`sql_tutorial`;#删除资料库每个完整语句后必须加分号创建和删除表格MySQL的一些资料形态:INT整数DECIMAL(3,2)有小数点的数例如2.33......
  • MySQL 8.0 instant 添加和删除列
    MySQL8.0.12开始,以下的altertable操作支持ALGORITHM=INSTANT算法:1.添加新的列。即instantaddcolumn2.添加或者删除虚拟列3.添加或者删除列的默认值4.修改enum、set类型列的定义5.修改索引类型6.重命名表 支持ALGORITHM=INSTANT算法的操作,只会修改数据字......
  • linux下部署MySQL服务
    linux下部署MySQL服务1、安装sudo-s调整为root下用户角色运行以下命令安装MySQL,输入Y继续sudoaptinstallmysql-server2、启动systemctlstartmysqld设置MySQL开机自启动(可选)systemctlenablemysqld3、检查运行状态systemctlstatusmysqld4、配置MySQL用户......
  • MySQL
    库的增删改查(1)语法#增createdatabasedb1;createdatabasedb2charset='gbk'#查showdatabases;#查所有的库showcreatedatabasedb1;#查单个#改alterdatabasedb2charset='utf-8'#删dropdatabasedb2;表的增删改查(1)语法#查看当前所在的库的名字......
  • 为什么@Bean还要标注initMetod
    当使用@Bean注解声明一个方法返回一个bean对象时,有时候我们会遇到需要在bean对象创建后执行一些初始化逻辑的情况。在这种情况下,我们可以使用initMethod属性来指定一个初始化方法。虽然在@Bean方法中直接调用初始化逻辑也是可行的,但为什么还要标注initMethod呢?代码清晰性和可维......
  • 在 Linux 系统上安装 mysql 5.7
    准备工作下载MySQL:下载页面、下载地址创建MySQL用户组、用户、相关目录、日志文件#创建新用户组groupaddmysql#创建用户mysql,指定所属用户组为mysql,禁止其登录useradd-r-gmysql-s/sbin/nologin#创建安装目录(可以自定义,这里以“/usr/local/mysql”为例)mk......
  • 记录--源码视角,Vue3为什么推荐使用ref而不是reactive
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助ref 和 reactive 是Vue3中实现响应式数据的核心API。ref 用于包装基本数据类型,而reactive用于处理对象和数组。尽管 reactive 似乎更适合处理对象,但 Vue3官方文档更推荐使用 ref。 我的想法,ref就......
  • MySQL——数据处理函数
    MySQL——数据处理函数数据处理函数又被称为单行处理函数,单行处理函数的特点:一个输入对应一个输出.语法格式:select单行处理函数(字段名)from表名;常见单行处理函数转换小写:lower()转换大写:upper()取子串:substr(),语法为substr(字段名,头,尾)。注意:起始下标是从1开......
  • mysql锁表
    要查看MySQL数据库中的锁信息,可以使用以下方法之一:使用 SHOWFULLPROCESSLIST:这个命令将显示当前MySQL实例中正在执行的所有进程,包括它们所持有的锁信息。在终端中执行以下命令:sql复制代码SHOWFULLPROCESSLIST;这将列出当前连接到MySQL实例的所有客户端会话,并......
  • 开始学习web-sql注入
    web内容多且杂,不知道怎么下手开始学,那就先从sql注入开始学吧目前只在b站上找了一些课程,还有ctfwiki作为参考链接贴在下面:ctfwikihttps://www.bilibili.com/video/BV1c34y1h7So/?spm_id_from=333.337.search-card.all.click&vd_source=27b6c7c9811379b1cf1a595591fa3086要是能......