想当初我自己想出来用where 1=1的时候还高兴了一小会,毕竟把代码简化了许多。今天看到的书里面说会影响性能。摘要如下:

低效的“WHERE 1=1”

网上有不少人提出过类似的问题:“看到有人写了WHERE 1=1这样的SQL,到底是什么意 思?”。

其实使用这种用法的开发人员一般都是在使用动态组装的SQL。

让我们想像如下的场景:用户要求提供一个灵活的查询界面来根据各种复杂的条件来查询 员工信息,界面如下图:
界面中列出了四个查询条件,包括按工号查询、按姓名查询、按年龄查询以及按工资查询,

每个查询条件前都有一个复选框,如果复选框被选中,则表示将其做为一个过滤条件

。比如上图 就表示“检索工号介于DEV001和DEV008之间、姓名中含有J并且工资介于3000元到6000元的 员工信息”。

如果不选中姓名前的复选框,比如下图表示“检索工号介于DEV001和DEV008之 间并且工资介于3000元到6000元的员工信息”:
如果将所有的复选框都不选中,则表示表示“检索所有员工信息”,比如下图:
这里的数据检索与前面的数据检索都不一样,因为前边例子中的数据检索的过滤条件都是 确定的,而这里的过滤条件则随着用户设置的不同而有变化,这时就要根据用户的设置来动态组 装SQL了。当不选中年龄前的复选框的时候要使用下面的SQL语句: SELECT * FROM T_Employee WHERE FNumber BETWEEN 'DEV001' AND 'DEV008' AND FName LIKE '%J%' AND FSalary BETWEEN 3000 AND 6000 而如果不选中姓名和年龄前的复选框的时候就要使用下面的SQL语句: SELECT * FROM T_Employee WHERE FNumber BETWEEN 'DEV001' AND 'DEV008' AND FSalary BETWEEN 3000 AND 6000 而如果将所有的复选框都不选中的时候就要使用下面的SQL语句: SELECT * FROM T_Employee

要实现这种动态的SQL语句拼装,我们可以在宿主语言中建立一个字符串,然后逐个判断各 个复选框是否选中来向这个字符串中添加SQL语句片段。这 里 有 一 个问题就是当有复选框被选中 的时候SQL语句是含有WHERE子句的,而当所有的复选框都没有被选中的时候就没有WHERE子句 了,因此在添加每一个过滤条件判断的时候都要判断是否已经存在WHERE语句了,如果没有 WHERE语句则添加WHERE语句。在判断每一个复选框的时候都要去判断,这使得用起来非常麻烦, “聪明的程序员是会偷懒的程序员”,因此开发人员想到了一个捷径:为SQL语句指定一个永远 为真的条件语句(比如“1=1”),这样就不用考虑WHERE语句是否存在的问题了。

伪代码如下

  String sql = " SELECT * FROM T_Employee WHERE 1=1";

  if(工号复选框选中) {

      sql.appendLine("AND FNumber BETWEEN '"+工号文本框1内容+"' AND '"+工号 文本框2内容+"'");

  }
  if(姓名复选框选中) {
sql.appendLine("AND FName LIKE '%"+姓名文本框内容+"%'");
} if(年龄复选框选中) {
sql.appendLine("AND FAge BETWEEN "+年龄文本框1内容+" AND "+年龄文本框2 内容);
}
executeSQL(sql);

这样如果不选中姓名和年龄前的复选框的时候就会执行下面的SQL语句: SELECT * FROM T_Employee WHERE 1=1 AND FNumber BETWEEN 'DEV001' AND 'DEV008' AND FSalary BETWEEN 3000 AND 6000 而如果将所有的复选框都不选中的时候就会执行下面的SQL语句: SELECT * FROM T_Employee WHERE 1=1 这看似非常优美的解决了问题,殊不知这样很可能会造成非常大的性能损失,因为使用添 加了“1=1”的过滤条件以后数据库系统就无法使用索引等查询优化策略,数据库系统将会被迫 对每行数据进行扫描(也就是全表扫描)以比较此行是否满足过滤条件,当表中数据量比较大的 时候查询速度会非常慢。因此如果数据检索对性能有比较高的要求就不要使用这种“简便”的方 式。下面给出一种参考实现,伪代码如下:

 private void doQuery() {
Bool hasWhere = false;
StringBuilder sql = new StringBuilder(" SELECT * FROM
T_Employee");
if(工号复选框选中) {
hasWhere = appendWhereIfNeed(sql, hasWhere);
sql.appendLine("FNumber BETWEEN '"+工号文本框1内容+"' AND '"+工号 文本框2内容+"'");
}
if(姓名复选框选中) {
hasWhere = appendWhereIfNeed(sql, hasWhere); sql.appendLine("FName LIKE '%"+姓名文本框内容+"%'");
}
if(年龄复选框选中) {
hasWhere = appendWhereIfNeed(sql, hasWhere); sql.appendLine("FAge BETWEEN "+年龄文本框1内容+" AND "+年龄文本框2 内容);
}
executeSQL(sql);
}
private Bool appendWhereIfNeed(StringBuilder sql,Bool hasWhere) {
if(hasWhere==false) {
sql. appendLine("WHERE");
} else {
sql. appendLine("AND");
}
}

这里演示的将检索参数值直接拼接到 SQL中的做法是有一定的问题的,会造成性能问题以及注入漏洞攻 击。为了降低问题的复杂度,这里规避了这个问题,在本书的后续章节将会详细讲解。

HAVING 语句 有的时候需要对部分分组进行过滤,比如只检索人数多余1个的年龄段,

有的开发人员会使 用下面的SQL语句: SELECT FAge,COUNT(*) AS CountOfThisAge FROM T_Employee GROUP BY FAge WHERE COUNT(*)>1 可以在数据库系统中执行下面的SQL的时候,数据库系统会提示语法错误,

这是因为聚合函数不能在WHERE语句中使用,必须使用HAVING子句来代替,

比如: SELECT FAge,COUNT(*) AS CountOfThisAge FROM T_Employee GROUP BY FAge HAVING COUNT(*)>1

符合条件中用where 1=1影响效率以及having和where的区别的更多相关文章

  1. where 1=1影响效率以及having和where的区别

    低效的“WHERE 1=1” 网上有不少人提出过类似的问题:“看到有人写了WHERE 1=1这样的SQL,到底是什么意 思?”. 其实使用这种用法的开发人员一般都是在使用动态组装的SQL. 让我们想像 ...

  2. Excel中用countif和countifs统计符合条件的个数 good

    countif单条件统计个数   1 就以下表为例,统计总分大于(包含等于)400的人数. 2 在J2单元格输入公式=COUNTIF(I2:I22,">=400") 3 回车 ...

  3. SQL where 条件顺序对性能的影响有哪些

    经常有人问到oracle中的Where子句的条件书写顺序是否对SQL性能有影响,我的直觉是没有影响,因为如果这个顺序有影响,Oracle应该早就能够做到自动优化,但一直没有关于这方面的确凿证据.在网上 ...

  4. Entity Framework 使用注意:Where查询条件中用到的关联实体不需要Include

    来自博客园开发团队开发前线最新消息: 在Entity Framework中,如果实体A关联了实体B,你想在加载实体A的同时加载实体B.通常做法是在LINQ查询中使用Include().但是,如果你在查 ...

  5. mysql随机查询符合条件的几条记录

    随机查询,方法可以有很多种.比如,查询出所有记录,然后随机从列表中取n条记录.使用程序便可实现.可是程序实现必须查询出所有符合条件的记录(至少是所有符合条件的记录id),然后再随机取出n个id,查询数 ...

  6. 优化 : Oracle数据库Where条件执行顺序 及Where子句的条件顺序对性能的影响

    .Oracle数据库Where条件执行顺序: 由于SQL优化起来比较复杂,并且还会受环境限制,在开发过程中,写SQL必须必须要遵循以下几点的原则: 1.ORACLE采用自下而上的顺序解析WHERE子句 ...

  7. JavaScript利用replace更改所有符合条件字符

    利用replace替换字符串时,在正常使用情况下默认只能更改匹配到的第一个字符 var a=new String("fffffddd"); console.log(a.replac ...

  8. 遍历List集合,删除符合条件的元素

    List集合的遍历有三种方式:增强for循环,普通for循环,Iterator迭代器遍历 如果只是对集合进行遍历,以上三种循环都可正常遍历: (1)增强For循环遍历List集合 List<St ...

  9. PHP函数preg_replace() 正则替换所有符合条件的字符串

    PHP preg_replace() 正则替换,与JavaScript 正则替换不同,PHP preg_replace() 默认就是替换所有符号匹配条件的元素. preg_replace (正则表达式 ...

随机推荐

  1. php写入数据到mysql数据库中出现乱码解决方法

    乱码情况: 在选择数据库前加入一句代码即可 mysql_query("set names utf8"); 最后效果

  2. JSONP解决跨域方案

    一.jsonp原理 本质并不是ajax,只是执行了跨域js,所以该方式只支持get方式 html中,所有带src属性的标签都可以跨域script img iframe 所以,可以通过script加载其 ...

  3. linux开发核心理解

    目录 授权 致谢 序言 更新纪录 导读 如何写作科技文档 I. 气候 1. GUI? CLI? 2. UNIX 缩写风格 3. 版本号的迷雾 4.   Vim 还是 Emacs 5.   DocBoo ...

  4. vc++2008 采用GSoap访问 WebService

    (转http://www.cppblog.com/yeqing/articles/12762.html) 前一阶段写gSOAP 的文章没保存好,后来想写的,越学越没有写的勇气了,感觉自己很菜,但是现在 ...

  5. nodejs渲染到页面的理解

    一般逻辑都是: 打开页面,前端发请求到服务端,服务端返回数据到前端,前端根据数据生成DOM节点,然后append到DOM中. 如果是nodejs渲染到页面,我的理解是: 打开页面,服务端直接把数据查询 ...

  6. kubernetes 学习 ingress

    ingress是Kubernetes 暴露服务的一种方式. Ingress由两部分组成:Ingress Controller 和 Ingress 服务.     Ingress Contronler ...

  7. 为什么每个浏览器都有Mozilla字样

    你是否好奇标识浏览器身份的User-Agent,为什么每个浏览器都有Mozilla字样?Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 ( ...

  8. Oracle 在约束中使用正则表达式

    ALTER TABLE mytest ADD CONSTRAINT CK_REG CHECK(REGEXP_LIKE(TEST, '^[0-9]{1,3}(\.[0-9]){0,1}$'));

  9. nginx isis

    Nginx+IIS简单的部署   随着互联网项目用户访问量不断上升,单点web服务器是无法满足大型高并发高负载的业务处理的,为了给web服务器做负载均衡方案,打算采用Nginx搭建负载均衡服务器,把用 ...

  10. 问题:C#控制台;结果:C#限制程序只能运行一個实例 (防多开)

    C# Console类的具体用法 作者: 字体:[增加 减小] 类型:转载 时间:2013-03-08 这篇文章主要介绍C# Console类的具体用法,需要的朋友可以参考下   Console.Wr ...