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

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 本文探讨了在SQL查询中使用`1=1`的现象及其背后的原因与问题。开发人员有时使用`1=1`作为始终为真的条件来方便动态构建SQL语句,但这样做可能会带来性能问题,尽管现代数据库查询优化器可能能优化掉这种条件,但在复杂查询或特定系统中仍可能影响效率。此外,`1=1`还降低了代码的可读性和跨数据库的兼容性。建议使用更佳实践,如MyBatis的动态SQL标签或Entity Framework的函数式查询,以避免不必要的条件。代码质量的重要性在于每一行代码都应有其明确的目的,避免浪费计算资源。

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

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

为什么会使用 1=1?

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

就像下边这样:

ini

复制代码

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

xml

复制代码

<!-- 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 的方法:

ini

复制代码

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语句时也应该避免添加无意义的条件。

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


转载来源:https://juejin.cn/post/7337513754970095667

相关文章
|
SQL Cloud Native 关系型数据库
ADBPG(AnalyticDB for PostgreSQL)是阿里云提供的一种云原生的大数据分析型数据库
ADBPG(AnalyticDB for PostgreSQL)是阿里云提供的一种云原生的大数据分析型数据库
2034 1
|
分布式数据库 Hbase 存储
带你读《HBase原理与实践》之一:HBase概述
Apache HBase是基于Apache Hadoop构建的一个高可用、高性能、多版本的分布式NoSQL数据库,是Google BigTable的开源实现,通过在廉价服务器上搭建大规模结构化存储集群,提供海量数据高性能的随机读写能力。
|
6月前
|
存储 SQL 分布式计算
MaxCompute 聚簇优化推荐原理
基于历史查询智能推荐Clustered表,显著降低计算成本,提升数仓性能。
406 4
MaxCompute 聚簇优化推荐原理
|
供应链 搜索推荐 安全
唯品会Vip商品详情 API 接口:开发应用与收益深度剖析
唯品会Vip商品详情API接口,作为电商数据交互的枢纽,提供详尽的商品信息与动态数据,助力开发者、商家及市场分析者洞察市场趋势、优化商品推荐、提升用户体验,从而实现销售额增长、利润空间拓展及用户忠诚度加固,推动电商行业创新发展。
657 16
|
SQL 数据库 开发者
SQL中为什么不要使用1=1?
【8月更文挑战第11天】在SQL查询语句中,偶尔会遇到使用1=1作为WHERE子句一部分的情况,这种做法看似无害,实则隐藏着一些潜在的问题和更好的替代方案。本文将深入探讨为什么不建议在SQL中使用1=1,并分享更优化的查询构建策略。
344 2
|
JSON Dart 前端开发
鸿蒙应用开发从入门到入行 - 篇7:http网络请求
在本篇文章里,您将掌握鸿蒙开发工具DevEco的基本使用、ArkUI里的基础组件,并通过制作一个简单界面掌握使用
674 8
|
人工智能 算法 JavaScript
无界SaaS与AI算力算法,链接裂变万企万商万物互联
本文介绍了一种基于无界SaaS与AI算力算法的商业模式的技术实现方案,涵盖前端、后端、数据库及AI算法等关键部分。通过React.js构建用户界面,Node.js与Express搭建后端服务,MongoDB存储数据,TensorFlow实现AI功能。提供了项目结构、代码示例及部署建议,强调了安全性、可扩展性和性能优化的重要性。
|
存储 JavaScript 前端开发
父子组件通信:有效地在Vue组件树中传递数据
【4月更文挑战第24天】Vue.js中的组件通信是实现可维护和可扩展代码的关键。遵循单向数据流原则,数据从父组件通过`props`传给子组件,子组件通过`$emit`触发事件响应。常用通信方式包括:1) `Props`和`Events`基础通信;2) `Provide / Inject`跨级通信;3) 使用Vuex管理复杂状态;4) 共享祖先组件或Vuex处理非父子组件通信;5) 少量使用`ref`和`$parent / $children`直接访问。选择合适的方式能优化应用性能和用户体验。
310 0
|
SQL 自然语言处理 监控
Elasticsearch 基础检索(全文检索/多语言检索/地理位置查询)
Elasticsearch是一个基于Lucene的实时的分布式搜索和分析引擎,设计用于云计算中能够达到实时搜索,稳定,可靠,快速,并支持RESTFUL风格的url访问。全文检索、多语言检索以及基于地理位置信息检索在Elasticsearch上应用广泛,本场实验将分别介绍如何使用Elasticsearch8.5版本进行全文检索、多语言检索和地理位置查询三个Elasticsearch基础检索子场景的实现。
19553 7
Elasticsearch 基础检索(全文检索/多语言检索/地理位置查询)