0

我的应用程序中有一种情况是显示符合不同标准的数据计数。由于计数的性能随着数据库的增长而下降,我们决定使用 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子句,以便我可以显示每个类别中的文档是否可用。

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

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

我已将上面的查询更改为与下面的每个都存在子句的联合。

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 秒来生成输出。

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

无论如何要优化/重写这个查询

谢谢你

4

1 回答 1

3

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

惊喜,惊喜。运行相当于同一查询八次不会比运行一次查询快。

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

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

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

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

现在您还需要了解您的数据。选择的数据是均匀分布在整个表中还是有簇?某些项目、所有者或经理是否拥有比其他项目更多的记录?该分布如何影响性能?

请记住,调优是一门科学,而且很复杂:关于这个主题的书籍有很多,有些人作为性能故障排除者过着很好的生活。它需要有关您的系统的大量信息,包括有关您的应用程序做什么的知识以及关于您的数据库正在执行哪些活动的低级信息。我们可以帮助您寻找更高效的解决方案,但我们不能只看一个不靠谱的查询并告诉您如何重写以使其运行得更快。

于 2012-06-22T11:56:26.873 回答