最近看几个老项目的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标签(如 )来构建条件查询。 标签会自动处理首条条件前的 AND 或 OR。当没有满意条件的 或其他条件标签时, 标签内部的一切内容将被忽略,从而不会生成多余的 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句子时也应该防止添加无意义的条件。

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