低效的“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” 网上有不少人提出过类似的问题:“看到有人写了W ...

  2. FOR ALL ENTRIES IN 与 INNER JOIN 写在一个SQL上影响效率

    SELECT likp~vbeln likp~lfart lips~werks likp~kunnr INTO CORRESPONDING FIELDS OF TABLE it_likps FROM ...

  3. 去掉影响效率的where 1=1

    最近看了篇文章,觉得挺有道理.实际项目中,我们进行sql条件过滤,我们不能确定是不是有条件.也不能确定条件的个数.大多数人会先把sql语句组装为: 这样,如果有其他过滤条件直接加上“and 其他条件” ...

  4. 在企业级开发中使用Try...Catch...会影响效率吗?

    感谢神啊.上帝及老天爷让我失眠,才能够有了本篇文章. 记得不久之前,公司一同事曾经说过:“如果是Winform开发,由于程序是在本地,使用try...catch不会有太大性能问题,可是如果是在web服 ...

  5. C# 拆箱与装箱 要严格控制,数量多起来严重影响效率

    int i = 5; object o = i; int j = (int)o; IComparer x = 5; 1. o的对象必须为一个引用,而数字5不是,则发生了装箱: 运行时将在堆上创建一个包 ...

  6. Java中List详解

    List是Java中比较常用的集合类,关于List接口有很多实现类,本文就来简单介绍下其中几个重点的实现ArrayList.LinkedList和Vector之间的关系和区别. List List 是 ...

  7. Java写算法题中那些影响你效率的细节(关于暴力破解算法题的细节处理)

    QQ讨论群:99979568 多交流才能进步 暂时写到这里,有不懂的欢迎评论, 如果有什么其他提高效率的细节,欢迎评论或者私信我,小编一定努力学习,争取早日分享给大家 如果大家嫌三连累的话,可以看看这 ...

  8. 【转】4G内存下MySQL修改配置文件以优化效率(来自discuz)

    摘要:公司网站访问量越来越大,MySQL自然成为瓶颈,因此最近我一直在研究 MySQL 的优化,第一步自然想到的是 MySQL 系统参数的优化,作为一个访问量很大的网站(日20万人次以上)的数据库. ...

  9. NOT IN查询效率低,用它的等效写法提高效率。

    最近在处理大数据量导入的时候,使用OPENROWSET将Excel导入到临时表中之后,需要对数据进行唯一性验证.这时候发现使用NOT IN严重影响效率,一条sql可能执行10分钟甚至更久.尝试改变写法 ...

随机推荐

  1. PHP条件运算符的“坑”

    今天遇到一个关于PHP 嵌套使用条件运算符(ternary expressions)的问题 现象 先来看一段C语言代码(test.c): #include<stdio.h> int mai ...

  2. 测试Mysql悲观锁

  3. Python之数字

    Python之数字 int(数字)===>在Python3中,int没有范围,在Python2中,int超出范围就叫长整型(Long). 浮点运算:单精度 float 双精度 double a: ...

  4. Python爬虫例子(笔记,不适合参考,愿意看的可以看看)

    话不多说,直接上代码: import re import csv #爬虫的一个小例子,爬的是百度贴吧(网页版)某个帖子的各个楼层的用户名,发言内容和发言时间(使用到了正则表达式) source3.tx ...

  5. i2c精简总结

    基本的i2c的编程包括:读数据,写命令,写数据 有关i2c的时序需要的话查看这里http://blog.csdn.net/qqliyunpeng/article/details/41511347 1. ...

  6. Python接口测试之对MySQL的操作(六)

    本文章主要来说python对mysql数据库的基本操作,当然,前提是已经搭建了python环境和搭建了Mysql 数据库的环境,python操作mysql数据库提供了MySQLdb库,下载的地址为: ...

  7. BNUOJ 6023 畅通工程续

    畅通工程续 Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 1874 ...

  8. 九度oj 题目1052:找x

    题目1052:找x 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:9901 解决:5098 题目描述: 输入一个数n,然后输入n个数值各不相同,再输入一个值x,输出这个值在这个数组中的下标 ...

  9. Java Class 利用classpath来获取源文件地址

    利用classpath来获取源文件地址 @author ixenos 应用场景 Properties props = new Properties(); /** * . 代表java命令运行的目录 * ...

  10. 58. Spring Boot国际化(i18n)【从零开始学Spring Boot】

    国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式.它要求从产品中抽离所有地域语言,国家/地区和文化相关的元素.换言之,应用程序的功能和代码设计考虑在不 ...