符合条件中用where 1=1影响效率以及having和where的区别
想当初我自己想出来用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的区别的更多相关文章
- where 1=1影响效率以及having和where的区别
低效的“WHERE 1=1” 网上有不少人提出过类似的问题:“看到有人写了WHERE 1=1这样的SQL,到底是什么意 思?”. 其实使用这种用法的开发人员一般都是在使用动态组装的SQL. 让我们想像 ...
- Excel中用countif和countifs统计符合条件的个数 good
countif单条件统计个数 1 就以下表为例,统计总分大于(包含等于)400的人数. 2 在J2单元格输入公式=COUNTIF(I2:I22,">=400") 3 回车 ...
- SQL where 条件顺序对性能的影响有哪些
经常有人问到oracle中的Where子句的条件书写顺序是否对SQL性能有影响,我的直觉是没有影响,因为如果这个顺序有影响,Oracle应该早就能够做到自动优化,但一直没有关于这方面的确凿证据.在网上 ...
- Entity Framework 使用注意:Where查询条件中用到的关联实体不需要Include
来自博客园开发团队开发前线最新消息: 在Entity Framework中,如果实体A关联了实体B,你想在加载实体A的同时加载实体B.通常做法是在LINQ查询中使用Include().但是,如果你在查 ...
- mysql随机查询符合条件的几条记录
随机查询,方法可以有很多种.比如,查询出所有记录,然后随机从列表中取n条记录.使用程序便可实现.可是程序实现必须查询出所有符合条件的记录(至少是所有符合条件的记录id),然后再随机取出n个id,查询数 ...
- 优化 : Oracle数据库Where条件执行顺序 及Where子句的条件顺序对性能的影响
.Oracle数据库Where条件执行顺序: 由于SQL优化起来比较复杂,并且还会受环境限制,在开发过程中,写SQL必须必须要遵循以下几点的原则: 1.ORACLE采用自下而上的顺序解析WHERE子句 ...
- JavaScript利用replace更改所有符合条件字符
利用replace替换字符串时,在正常使用情况下默认只能更改匹配到的第一个字符 var a=new String("fffffddd"); console.log(a.replac ...
- 遍历List集合,删除符合条件的元素
List集合的遍历有三种方式:增强for循环,普通for循环,Iterator迭代器遍历 如果只是对集合进行遍历,以上三种循环都可正常遍历: (1)增强For循环遍历List集合 List<St ...
- PHP函数preg_replace() 正则替换所有符合条件的字符串
PHP preg_replace() 正则替换,与JavaScript 正则替换不同,PHP preg_replace() 默认就是替换所有符号匹配条件的元素. preg_replace (正则表达式 ...
随机推荐
- php写入数据到mysql数据库中出现乱码解决方法
乱码情况: 在选择数据库前加入一句代码即可 mysql_query("set names utf8"); 最后效果
- JSONP解决跨域方案
一.jsonp原理 本质并不是ajax,只是执行了跨域js,所以该方式只支持get方式 html中,所有带src属性的标签都可以跨域script img iframe 所以,可以通过script加载其 ...
- linux开发核心理解
目录 授权 致谢 序言 更新纪录 导读 如何写作科技文档 I. 气候 1. GUI? CLI? 2. UNIX 缩写风格 3. 版本号的迷雾 4. Vim 还是 Emacs 5. DocBoo ...
- vc++2008 采用GSoap访问 WebService
(转http://www.cppblog.com/yeqing/articles/12762.html) 前一阶段写gSOAP 的文章没保存好,后来想写的,越学越没有写的勇气了,感觉自己很菜,但是现在 ...
- nodejs渲染到页面的理解
一般逻辑都是: 打开页面,前端发请求到服务端,服务端返回数据到前端,前端根据数据生成DOM节点,然后append到DOM中. 如果是nodejs渲染到页面,我的理解是: 打开页面,服务端直接把数据查询 ...
- kubernetes 学习 ingress
ingress是Kubernetes 暴露服务的一种方式. Ingress由两部分组成:Ingress Controller 和 Ingress 服务. Ingress Contronler ...
- 为什么每个浏览器都有Mozilla字样
你是否好奇标识浏览器身份的User-Agent,为什么每个浏览器都有Mozilla字样?Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 ( ...
- Oracle 在约束中使用正则表达式
ALTER TABLE mytest ADD CONSTRAINT CK_REG CHECK(REGEXP_LIKE(TEST, '^[0-9]{1,3}(\.[0-9]){0,1}$'));
- nginx isis
Nginx+IIS简单的部署 随着互联网项目用户访问量不断上升,单点web服务器是无法满足大型高并发高负载的业务处理的,为了给web服务器做负载均衡方案,打算采用Nginx搭建负载均衡服务器,把用 ...
- 问题:C#控制台;结果:C#限制程序只能运行一個实例 (防多开)
C# Console类的具体用法 作者: 字体:[增加 减小] 类型:转载 时间:2013-03-08 这篇文章主要介绍C# Console类的具体用法,需要的朋友可以参考下 Console.Wr ...