上一篇我们讲完SQL动态查询,本节我们继续来讲解SQL动态查询中存在的问题。


当我们创建存储过程调用存储过程时,若筛选条件有值则过滤,没有值则返回所行记录,类似如下查询:


WHERE (SomeColumn = @col OR @col IS NULL)


这样查询会存在什么问题呢?性能会不会有问题呢,这个是我们本节需要深入探讨的问题。


接下来我们创建如下测试表并插入测试数据,如下:

WHERE Column=@Param OR @Param IS NULL有问题?_java

对于动态SQL条件筛选过滤我们利用WHERE 1 = 1来拼接。接下来我们使用一般SQL语句和动态查询并比较其IO,如下:

WHERE Column=@Param OR @Param IS NULL有问题?_java_02

 

WHERE Column=@Param OR @Param IS NULL有问题?_java_03

WHERE Column=@Param OR @Param IS NULL有问题?_java_04


我们能够看到动态SQL查询逻辑读取只读取2次,而另外一般SQL语句查询逻辑读取7次,同时我们看到SQL动态查询计划执行的是索引查找,而一般SQL语句则是索引扫描。


看来执行一般SQL语句不会走索引查找,将导致性能问题,在开头我们就讲过筛选条件有值则过滤,无值则查询所有数据,那么我们完全可以借助ISNULL来查询,下面我们用ISNULL来改变一般语句筛选条件,看看是否会走索引查找呢?

WHERE Column=@Param OR @Param IS NULL有问题?_java_05


WHERE Column=@Param OR @Param IS NULL有问题?_java_06

WHERE Column=@Param OR @Param IS NULL有问题?_java_07

我们看到结果依然是走索引扫描,没有任何改变。是不是就没有解决之道了呢?我们来改变一般SQL语句查询方式,如下:

WHERE Column=@Param OR @Param IS NULL有问题?_java_08

如上只能是勉勉强强解决了问题,因为只是针对一个参数,如果有多个参数要进行IF...ELSE..,那可就傻逼了。从本质上解决这个问题我们需要利用可选项重新编译。如下:

WHERE Column=@Param OR @Param IS NULL有问题?_java_09


WHERE Column=@Param OR @Param IS NULL有问题?_java_10

WHERE Column=@Param OR @Param IS NULL有问题?_java_11


当利用条件筛选过滤数据时,如果条件有值则过滤,否则返回所有行记录。如果执行一般SQL语句和动态SQL,那么动态SQL会走索引查找,而一般SQL语句将导致索引扫描,此时需要加上OPTION(RECOMPILE)才走索引查找。