Oracle - 使用multiple存在来检查记录可用性

时间:2012-06-22 06:56:03

标签: performance oracle query-optimization exists

我的应用程序中有一种情况,用于显示符合不同标准的数据计数。由于计数的性能随着数据库的增长而降低,我们决定使用exists子句仅显示可用性信息。

以下是我的表结构

Table: DocInfo
---------------------------------------
DocId       number
DocName     varchar(250)
DocStatus   number
SignedBy    number
ForwardedBy number
ForwardCount    number
DocOwner    number
MgrID       number
ProjectId   number

进行计数的当前查询就像这样

SELECT NVL(SUM(CASE
                 WHEN (DocStatus IN (1150,1155,1170,1182,1190) AND
                       DocOwner=56366 AND
                       ForwardCount=0)
                   THEN 1
                   ELSE 0
               END), 0) "ForReview",
       NVL(SUM(CASE
                 WHEN (DocStatus IN (1200) And
                       MgrID = 56366 AND
                       ForwardCount = 0 )
                   THEN 1
                   ELSE 0
               END), 0) "Accepted" , 
       NVL(SUM(CASE
                 WHEN (DocStatus IN (1150,1155,1170,1182,1190) AND
                       DocOwner=56366 AND
                       MgrID = 0 )
                   THEN 1
                   ELSE 0
               END), 0) "Waiting"
  FROM DocInfo 
  WHERE ProjectId = 313 and
        (DocOwner = 56366 or MgrID = 56366)

我需要将计数更改为exists子句,以便我可以显示每个类别中的文档是否可用。

由于此更改是为了提高性能,因此不建议将其作为不同的查询运行。请帮助我,我的知识有限。

很抱歉错过了我已尝试过的部分。

我已将上述查询更改为带有exists子句的联合,如下所示。

SELECT 'ForReview' AS A
  FROM DUAL
  WHERE EXISTS (SELECT NULL
                  FROM DocInfo 
                  WHERE ProjectId = 313 and
                        (DocOwner = 56366 or MgrID = 56366)  and
                        (DocStatus IN (1150,1155,1170,1182,1190) AND
                         DocOwner=56366 AND
                         ForwardCount=0)) 
UNION 
  SELECT 'Accepted' AS A
    FROM DUAL
    WHERE EXISTS (SELECT NULL
                    FROM DocInfo
                    WHERE ProjectId = 313 and
                          (DocOwner = 56366 or MgrID = 56366) and
                          (DocStatus IN (1200) And
                           MgrID = 56366 AND
                           ForwardCount = 0 )) 
UNION
  SELECT 'Waiting' AS A
    FROM DUAL
    WHERE EXISTS (SELECT NULL
                    FROM DocInfo
                    WHERE ProjectId = 313 and
                          (DocOwner = 56366 or MgrID = 56366) and
                          (DocStatus IN (1150,1155,1170,1182,1190) AND
                           DocOwner=56366 AND
                           MgrID = 0)) 

我只提到了3个条件,而我的实际应用程序有8个不同的条件要添加到此查询中。因此,当我有8个Exists子句时,它在内部运行为8个不同的查询,实际上它需要更多时间 - 整个联合查询中的单个段只需要560毫秒,而所有查询一起花费大约7秒来生成输出。

由于我的要求仅是识别任何此类记录的可用性,因此我不想浏览整个记录集并对其进行计数。

无论如何都要优化/重写此查询

谢谢

1 个答案:

答案 0 :(得分:3)

  

"所以当我有8个Exists子句时,它在内部运行为8个不同   查询,实际上它需要更多的时间 - 单个段   整个联合查询只需560毫秒,而所有查询一起   大约需要7秒钟来生成输出。"

惊喜,惊喜。运行相同的查询次的速度并不比运行该查询一次快。

现在确实EXISTS可以更快,因为它只需要找到符合给定条件的单行,而不是检索整个数据集。但是,您刚刚将检索到的数据转移到WHERE子句中,因此数据库仍然需要执行相同的工作量。事实上,它显然做了很多工作,因为7s > (560ms * 8)

要正确解决问题,您需要了解数据库的工作原理以及如何调整它。 Find out more

首先,定义一个调整目标。您的原始查询需要半秒才能运行:这不是快速闪电,但速度非常快。为什么这是个问题?你想以多快的速度运行它?

接下来,运行EXPLAIN PLAN。查询是否使用索引?它的索引使用效率如何>选择了多少百分比的行?

现在您还需要低估数据。所选数据是均匀分布在整个表中还是存在集群?有些项目,业主或经理比其他项目有更多的记录吗?这种分布如何影响绩效?

请记住,调整是一门科学,而且很复杂:有关于这个主题的全书,有些人作为性能故障排除者做了非常好的生活。它需要大量有关系统的信息,包括应用程序的功能以及数据库正在执行的活动的低级信息。我们可以帮助您找到更高效的解决方案,但我们不能只看一个简单的查询,并告诉您如何重写,以便更快地运行。