码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-02-06 13:06:39      阅读:190      评论:0      收藏:0      [点我收藏+]

标签:span   注入   query   函数   条件语句   部分   程序员   漏洞   数据检索   

低效的“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的区别

标签:span   注入   query   函数   条件语句   部分   程序员   漏洞   数据检索   

原文地址:https://www.cnblogs.com/chenglc/p/8421476.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!