低效能的”where1=1”

网上有不少人提出过类似的问题:“看到有人写了where 1=1这种sql,究竟是什么意思?”。事实上使用这种使用方法的开发者一般都是在使用动态数组的sql。


让我们想象例如以下的场景:用户要求提供一个灵活的查询界面来依据各种复杂的条件查询员工信息,界面例如以下图:



界面中列出了四个查询条件,包含按工号查询、按姓名查询、按年两查询以及按工资查询。每一个查询条件前都有个复选框,假设复选框被选中,则表示将其作为一个过滤条件。

比方上图就表示“检索工号介于001和008之间、姓名中含有J而且工资介于3000到6000的员工信息”。

假设不选中姓名前的复选框,比方下图表示“检索工号介于001和008之间

而且工资介于3000到6000的员工信息”:




假设全部的复选框都不选中,则表示“检索全部员工信息”,比方下图:




这里的数据检索与前面的检索不一样,由于前边样例中的数据检索的过滤条件都是确定的。而这里的过滤条件则随着用户设置的不同而有变化,这时就要依据用户的设置来动态

组装sql了。当不选中年龄前的复选框的时候要使用以下的SQL语句:


SELECT * FROM T_Employee
WHERE FNumber BETWEEN '001' AND '008'
AND FName LIKE '%J%'
AND FSalary BETWEEN 3000 AND 6000

而假设不选中姓名和年龄前的复选框的时候就要使用以下的SQL语句:


SELECT * FROM T_Employee
WHERE FNumber BETWEEN '001' AND '008'
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");
}
}






原文地址:https://www.cnblogs.com/gcczhongduan/p/5196513.html