WHERE-CASE子句子查询性能

时间:2014-04-25 14:41:11

标签: sql sql-server-2012 subquery case database-performance

该问题可以特定于SQL服务器。 当我写一个查询,如:

SELECT * FROM IndustryData WHERE Date='20131231'
AND ReportTypeID = CASE WHEN (fnQuarterDate('20131231')='20131231') THEN  1 
                        WHEN (fnQuarterDate('20131231')!='20131231') THEN  4
                        END;

对于表格的每一行,是否在Where子句内的Case中调用函数调用fnQuarterDate(或任何子查询)?

如果我事先在变量中得到函数的(或任何子查询)值,那将会更好:

DECLARE @X INT
IF fnQuarterDate('20131231')='20131231'
SET @X=1 
ELSE
SET @X=0
SELECT * FROM IndustryData WHERE Date='20131231'
AND ReportTypeID = CASE WHEN (@X = 1) THEN  1 
                        WHEN (@X = 0) THEN  4
                        END;

我知道在MySQL中,如果WHERE子句中的IN(..)内有子查询,则会对每一行执行,我只是想为SQL SERVER找到相同的内容。

...

刚填充的表格大约有30K行,并找出时差:

查询1 = 70毫秒;查询2 = 6毫秒。我认为这解释了它,但仍然不知道其背后的实际情况。

如果不是UDF而是有一个简单的子查询,那么会有什么区别吗?

3 个答案:

答案 0 :(得分:1)

我认为解决方案在理论上可以帮助您提高性能,但它也取决于标量函数实际执行的操作。我认为在这种情况下(我的猜测是将日期格式化为季度的最后一天)真的可以忽略不计。

您可能希望阅读此页面并提供建议的解决方法:

http://connect.microsoft.com/SQLServer/feedback/details/273443/the-scalar-expression-function-would-speed-performance-while-keeping-the-benefits-of-functions#

  

因为SQL Server必须在每一行上执行每个函数,所以使用任何函数都会产生类似性能损失的游标。

在Workarounds中,有一条评论

  

当我在连接列中使用标量UDF时,我遇到了同样的问题   表现太可怕了。在我用临时表替换UDF之后   它包含UDF的结果并在join子句中使用它   性能是数量级更好。 MS团队应该修复UDF   更可靠。

所以看来是的,这可能会提高性能。

您的解决方案是正确的,但我建议考虑改进SQL以使用ELSE,它看起来更清晰:

AND ReportTypeID = CASE WHEN (@X = 1) THEN  1 
                    ELSE 4
                    END;

答案 1 :(得分:0)

这取决于。见User-Defined Functions

  

实际执行查询中指定的函数的次数可能因优化程序生成的执行计划而异。一个示例是WHERE子句中的子查询调用的函数。子查询及其功能执行的次数可能因优化程序选择的不同访问路径而异。

答案 2 :(得分:0)

这种方法使用内联MySQL变量..." sqlvars"的查询别名将首先使用相关日期准备@dateBasis,然后根据对整个查询执行ONCE的函数调用来准备第二个变量@qtrReportType。然后,通过交叉连接(通过表之间的where where子句,因为sqlvars无论如何都被认为是单行),将使用这些值从IndustryData表中获取数据。

select
      ID.*
   from
      ( select 
              @dateBasis := '20131231',
              @qtrReportType := case when fnQuarterDate(@dateBasis) = @dateBasis 
                                then 1 else 4 end ) sqlvars,
      IndustryData ID
   where
          ID.Date = @dateBasis
      AND ID.ReportTypeID = @qtrReportType