为什么多个EXISTS中断查询

时间:2018-12-04 16:30:48

标签: sql sql-server exists

我试图包括一个新表,该表的值需要检查并包含在存储过程中。语句1是需要检查的现有表,而语句2是要检查的新表。

我目前有2个EXISTS条件,这些条件独立运行并产生期望的结果。我的意思是说,如果我注释掉声明1,则声明2有效,反之亦然。当我将它们放在一起时,查询不会完成,没有错误,但是会超时,这是意外的,因为每个语句只需要几秒钟。

我知道可能有更好的方法来执行此操作,但是在我这样做之前,我想知道为什么我似乎无法执行这样的多个存在语句? EXISTS子句中是否不存在多个WHERE条件?

SELECT *
FROM table1 S    
WHERE
--Statement 1
EXISTS 
(
   SELECT 1
   FROM table2 P WITH (NOLOCK)
      INNER JOIN table3 SA ON SA.ID = P.ID
   WHERE P.DATE = @Date AND P.OTHER_ID = S.ID
   AND 
   (
      SA.FILTER = ''
      OR 
      (
          SA.FILTER = 'bar'
          AND 
          LOWER(S.OTHER) = 'foo'
       )
    )
)
OR 
(
   --Statement 2
   EXISTS 
   (
      SELECT 1
      FROM table4 P WITH (NOLOCK)
         INNER JOIN table5 SA ON SA.ID = P.ID
      WHERE P.DATE = @Date 
            AND P.OTHER_ID = S.ID 
            AND LOWER(S.OTHER) = 'foo'
    )
)

编辑:我已包含查询详细信息。表1-5代表不同的表,没有重复的表。

2 个答案:

答案 0 :(得分:1)

评论太久了。

您所写的查询似乎正确。超时只能从执行计划中解决,但是这里有一些事情可能会发生或您可以从中受益。

  • @Date上进行参数嗅探。尝试对此值进行硬编码,看看您是否仍然得到相同的慢度
  • P.OTHER_IDP.DATEP.IDSA.ID上没有覆盖索引,这将导致对这些谓词进行表扫描
  • 上述列的索引不是最佳的(包括太多列等)
  • 您的查询为串行查询时可能会受益于并行性。
  • 在没有区分大小写的排序规则的数据库上使用LOWER函数(大多数情况下没有,尽管此函数不会使事情变慢很多)
  • 缓存中的查询计划不正确。尝试在底部添加OPTION (RECOMPILE),以便在you get a new query plan处添加。当比较两个查询的速度以确保它们不使用缓存的计划时,或者在另一个查询会歪曲结果的速度时,也不会这样做。

由于您的查询已超时,因此try including the estimated execution plan并将其发布到past the plan

答案 1 :(得分:0)

我发现将2 EXISTS置于WHERE条件下会使整个过程花费更长的时间。我发现已解决的问题是使用UNION并将EXISTS保留在单独的查询中。最终结果如下所示:

SELECT *
FROM table1 S    
WHERE
--Statement 1
   EXISTS 
   (
      SELECT 1
      FROM table2 P WITH (NOLOCK)
         INNER JOIN table3 SA ON SA.ID = P.ID
      WHERE P.DATE = @Date AND P.OTHER_ID = S.ID
      AND 
      (
         SA.FILTER = ''
         OR 
         (
             SA.FILTER = 'bar'
             AND 
             LOWER(S.OTHER) = 'foo'
          )
       )
   )

UNION

--Statement 2 
SELECT *
FROM table1 S    
WHERE
   EXISTS 
   (
      SELECT 1
      FROM table4 P WITH (NOLOCK)
         INNER JOIN table5 SA ON SA.ID = P.ID
      WHERE P.DATE = @Date 
            AND P.OTHER_ID = S.ID 
            AND LOWER(S.OTHER) = 'foo'
    )