在Select语句中的Case语句中存在函数需要FOREVER

时间:2013-11-06 20:40:46

标签: sql performance select exists case-when

我评论了有问题的代码。当我评论这部分时,运行大约需要5秒钟。

在额外条件下,大约需要一年时间(好像10分钟)。

感谢您的帮助!

SELECT  t.account as fstrAccount,
        t.idno as flngID,
        CASE    
        WHEN t.fstrType = '' THEN '' 

        WHEN wd.fstrWorkType    = 'SUSIN1'
        AND wd.fstrOwner        =  ' ' 
        AND wd.flngworkkey      =  wr.flngworkkey 
        AND wr.fstrAccountType  <> '007' 
        AND wr.fblnOpen         =  1 
        --AND   EXISTS  
        --  (SELECT 1 
        --  FROM    tblIndicator id
        --  WHERE   id.fstrIndicator   = 'EIWTCH' 
        --  AND id.flngVer         = 0 
        --  AND id.flngAccountKey  = wd.flngAccountKey)
        THEN 'Suspended for Audit Indicator - EIC Watch For'
        ELSE    t.fstrTaskSource + '_TYP_' + t.fstrType 
        END AS fstrType,

2 个答案:

答案 0 :(得分:4)

有时,EXISTS子句似乎会导致数据库行为不良,即使它应该落在索引上 - 复杂的查询只会混淆数据库优化器,最终会为主表中的每一行重新运行相关子查询

当所有其他优化都失败时,我通常会通过将其重写为左外连接并在连接表中的非NULL列上检查NULL来解决此问题。这有时使优化器可以理解查询,并且它进行了适当的索引连接。

对于您的SQL,它可能类似于:

SELECT 
   t.account as fstrAccount,
   t.idno as flngID,
   CASE
      ...
      AND wr.fblnOpen = 1
      AND NOT id.flngVer IS NULL
      ...
FROM
      ...
LEFT OUTER JOIN
    tblIndicator id
ON
    id.fstrIndicator = 'EIWTCH'
    AND id.flngVer = 0
    AND id.flngAccountKey = wd.flngAccountKey

这假设每个“wd”最多只有一个“id”,使用该ON子句。如果可以有多个匹配,则可以使用像MAX()这样的聚合函数,并依赖于如果没有记录则聚合函数将返回NULL的事实。在这种情况下,“AND NOT id.flngVer IS NULL”变为“AND NOT MAX(id.flngVer)IS NULL”。如果使用聚合函数,则还必须添加必要的GROUP BY语句。

答案 1 :(得分:2)

为了使用exists处理查询,SQL引擎需要评估该查询。您没有指定引擎,但大多数SQL引擎都不是特别擅长这一点。对于每一行,它们将遍历内部表tblIndicator。他们甚至可以为每一行执行此操作,以在评估case语句之前获取值。

提高性能的第一种方法是添加索引:

create index tblIndicator_fstrIndicator_flngVer_flngAccountKey on
    tblIndicator(fstrIndicator, flngVer, flngAccountKey)

提高性能的第二种方法是将其更改为left outer join。如果最多只有一行匹配,那么这很容易。如果您可能有多个匹配项,那么查询将需要更多工作。