博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
where 1=1影响效率以及having和where的区别
阅读量:2384 次
发布时间:2019-05-10

本文共 2993 字,大约阅读时间需要 9 分钟。

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

 

posted @
2018-02-06 11:29 阅读(
...) 评论(
...)

转载地址:http://yrcab.baihongyu.com/

你可能感兴趣的文章
PHP使用curl伪造IP地址和header信息
查看>>
代理服务器中的HTTP代理与SOCKS代理有什么区别?
查看>>
零基础Python学习路线,小白的进阶之路!
查看>>
CSS的23个垂直居中技巧,你都学会了吗?
查看>>
黑客攻击用的最短代码大揭秘,颠覆你的世界观!
查看>>
零基础的自学前端之路,当年的入坑之旅
查看>>
新手程序员?教你解决办法!基础都掌握了,动手敲代码就一脸懵逼
查看>>
程序员快速进阶学习到底要看书还是要看视频?
查看>>
web游戏框架哪家强?国内外精选优质框架分析及注意事项
查看>>
各行业都爱用什么编程语言开发?
查看>>
css3实现ps蒙版效果以及动画,炫酷吊炸天!
查看>>
程序员休息时间接私活遭公司辞退,不明觉厉?
查看>>
CSS 、JS实现浪漫流星雨动画
查看>>
新手网站建设指南(2)
查看>>
新手网站建设优化,这些网站为你提供数之不尽的免费素材!(3)
查看>>
HTML特殊字符显示(常用到的特殊符号,箭头相关,数学相关,标点,符号相关等)...
查看>>
40岁的程序员找不到工作,原来码农真的是碗青春饭
查看>>
2018年前端性能优化总结,这也是我做程序员的第五个年头了
查看>>
前端进阶(三)从0到1学AJAX,这篇就够了!
查看>>
强大的CSS:实现平行四边形布局效果
查看>>