积极答复者
where 条件中的IIF函数或是case when语句的性能问题怎么优化?

问题
-
有这样的应该场景,用户可以根据不同的日期自由切换(创建日期,记账日期)查询,在界面上根据单选按钮选择不同的日期类别查询。
存储过程里面这样写:(换成case when语句效果一样)
WHERE IIF(@datetype=0,CreatedDate,OrderDate) BETWEEN @sdate AND @edate
这样写之后不走索引,性能急剧下降。CreatedDate,OrderDate这两个字段都是有索引的,如何优化?
优化的前提条件是(1)不能拼接SQL,接拼SQL会带来其它性能问题并且不好维护。(2)不能用if else 语句判断@datetype的值写两段脚本,因为一个存储过程里面就会有好几处这样的代码,至少上百个存储过程,这样写增加不小的工作量而且不好维护。
还有什么办法优化吗?
答案
-
这个你还是拼语句吧, 用参数,不要直接把值拼到 sql 语句里面,把逻辑放到 sql 语句里面并不代表性能就好
比如 WHERE IIF(@datetype=0,CreatedDate,OrderDate) BETWEEN @sdate AND @edate
可以这样
if @datetype = 0
set @sql =@sql + 'where CreatedDate BETWEEN @sdate AND @edate'
else
set @sql = @sql + 'where OrderDate BETWEEN @sdate AND @edate'
exec sp_executesql @sql, N'@sdate datetime, @edate datetime', @sdate , @edate- 已标记为答案 Nan YuMicrosoft contingent staff, Moderator 2015年8月13日 9:38
-
通常程序里面拼会比存储过程里面拼好一些,存储过程里面拼,用 profile 看到的语句还是无法确定具体执行的是什么,需要根据参数值走一次
程序里面拼,传递给 sql server 的是具体执行的 sql, 可以明确知道在执行什么
- 已标记为答案 Nan YuMicrosoft contingent staff, Moderator 2015年8月13日 9:38
全部回复
-
这个你还是拼语句吧, 用参数,不要直接把值拼到 sql 语句里面,把逻辑放到 sql 语句里面并不代表性能就好
比如 WHERE IIF(@datetype=0,CreatedDate,OrderDate) BETWEEN @sdate AND @edate
可以这样
if @datetype = 0
set @sql =@sql + 'where CreatedDate BETWEEN @sdate AND @edate'
else
set @sql = @sql + 'where OrderDate BETWEEN @sdate AND @edate'
exec sp_executesql @sql, N'@sdate datetime, @edate datetime', @sdate , @edate- 已标记为答案 Nan YuMicrosoft contingent staff, Moderator 2015年8月13日 9:38
-
通常程序里面拼会比存储过程里面拼好一些,存储过程里面拼,用 profile 看到的语句还是无法确定具体执行的是什么,需要根据参数值走一次
程序里面拼,传递给 sql server 的是具体执行的 sql, 可以明确知道在执行什么
- 已标记为答案 Nan YuMicrosoft contingent staff, Moderator 2015年8月13日 9:38
-
因为这都是报表业务,存储过程比较长,没有程序,没用CLR,所以没在程序里面拼接。 如果拼接起来里面还有很多单引号、其它参数、#开头的临时表,不好处理,可读性也不好。
写if else 不用拼接的方法可读性也不好,脚本会变得好长也不好维护,稍不注意开发人员容易改错。
我换成这样的写法,效果也不好,有时候比WHERE IIF(@datetype=0,CreatedDate,OrderDate) BETWEEN @sdate AND @edate快,有时候又比这个慢
WHERE CreatedDate BETWEEN (CASE WHEN @datetype=0 THEN @sdate ELSE CreatedDate END) AND (CASE WHEN @datetype=0 THEN @edate ELSE CreatedDate END)
AND OrderDate BETWEEN (CASE WHEN @datetype=1 THEN @sdate ELSE OrderDate END) AND (CASE WHEN @datetype=1 THEN @edate ELSE OrderDate END)我现在想到的办法是写两个存储过程,一个存储过程用创建日期,一个日期用记账日期,改好一个存储过程直接复制一份替换对应的字段这样减少出错机会,外面再套一个存储过程进行日期类别逻辑判断
看看还有没有别的方法?