Select 语句中的 Case 语句中的 Exists 函数需要 FOREVER

Posted

技术标签:

【中文标题】Select 语句中的 Case 语句中的 Exists 函数需要 FOREVER【英文标题】:Exists function within a Case Statement within a Select Statement takes FOREVER 【发布时间】:2013-11-06 20:40:45 【问题描述】:

我注释掉了有问题的代码。当我注释掉这部分时,运行大约需要 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,

【问题讨论】:

您可能需要索引tblIndicator.fstrIndicatortblIndicator.flngAccountKey 为什么不在 tblIndicator 上添加一个额外的连接(左连接)到 from 子句,这样您就不必执行子查询并且存在。否则查询必须每次触发而不是一次。添加到左侧加入,添加 where 子句条件,然后简单地检查 id.flngaccountkey 上的空值,但要真正知道我们需要查看执行计划和结果。 我应该如何索引它们?任何例子,我之前从未明确地打算这样做(初学者) 【参考方案1】:

有时,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 语句。

【讨论】:

这很好地解释了为什么 EXISTS 子句可能有点糟糕。 (它们可能非常昂贵)在您尝试更改数据库之前,我当然会尝试更改您的查询,尤其是如果您是相对初学者。【参考方案2】:

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

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

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

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

【讨论】:

以上是关于Select 语句中的 Case 语句中的 Exists 函数需要 FOREVER的主要内容,如果未能解决你的问题,请参考以下文章

Select 语句中的 Case 语句中的 Exists 函数需要 FOREVER

在case语句中使用select语句中的参数[重复]

TRIGGER 中的 SELECT CASE 语句

SQL Server 2008 - SELECT 子句中的 Case / If 语句 [重复]

Select 语句中的案例

SQL查询语句SELECT中带有case when嵌套子查询判断的问题