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.fstrIndicator
或tblIndicator.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