比较oracle中的两个游标而不是使用MINUS

时间:2010-03-22 22:58:18

标签: performance oracle

以下查询运行时间超过3分钟,因为表包含大量数据:

  SELECT  RTRIM(LTRIM(A.HEAD)),
      A.EFFECTIVE_DATE,
    FROM   TABLE_1 A
    WHERE  A.TYPE_OF_ACTION='6'
    AND    A.EFFECTIVE_DATE >= ADD_MONTHS(SYSDATE,-15)  

    MINUS

    SELECT  RTRIM(LTRIM(B.head)),
      B.EFFECTIVE_DATE,
    FROM  TABLE_2 B

在我们的系统中,如果查询运行超过8秒,则查询将被终止。有没有办法单独运行查询..在游标中比较它们..比较然后得到结果?这样每个查询都将单独运行,而不是一个需要3分钟的大量查询。

如何比较两个游标来模仿MINUS

2 个答案:

答案 0 :(得分:1)

MINUS是一个设置操作,如果第二个查询的结果远离第一个查询,它也会删除重复项,如果它们出现在第一个集合中。 因此,显示的查询将始终必须在将TABLE_1返回给用户之前从TABLE_1构建完整的结果集。

如果您可以确定第一组中的trimemd头/生效日期没有重复(或者您不希望删除此类重复项),您可以尝试

SELECT  RTRIM(LTRIM(A.HEAD)), A.EFFECTIVE_DATE,
    FROM   TABLE_1 A
    WHERE  A.TYPE_OF_ACTION='6'
    AND    A.EFFECTIVE_DATE >= ADD_MONTHS(SYSDATE,-15)
    AND NOT EXISTS 
         (select 1 from table_2 b 
          where RTRIM(LTRIM(b.head)) = RTRIM(LTRIM(a.head))
          and b.effective_date = a.effective_date) )

这样查询可以更快地开始返回结果,特别是如果table_2非常小或者可以通过effective_date或head上的索引访问行。

PS。如果可以,请删除RTRIM(LTRIM())位。

PPS。仍然无法保证它会在8秒内返回。这取决于table_1的大小,以及type_of_action和/或effective_date的索引。

添加了:

您可以浏览

SELECT  RTRIM(LTRIM(A.HEAD)), A.EFFECTIVE_DATE,
    FROM   TABLE_1 A
    WHERE  A.TYPE_OF_ACTION='6'
    AND    A.EFFECTIVE_DATE >= ADD_MONTHS(SYSDATE,-15)

并在返回时忽略行

    select 1 from table_2 b 
      where RTRIM(LTRIM(b.head)) = :1
      and b.effective_date = :1
      and rownum =1

但完全执行肯定需要更长时间。也许数量级更长(即小时),具体取决于每个table_2检查需要多长时间。不完全确定使用什么标准进行截止(调用持续时间或打开SQL游标的持续时间),因此它可能会关闭外部游标。并且根据table_1的大小/索引/内容,外部游标可能仍然不会返回时间范围内的第一行。

table_1,table_2中有多少行以及哪些索引可用?

答案 1 :(得分:0)

MINUS与“获取第一个查询的所有行,然后从该集合删除同样位于第二个查询中的行”相同,因此您可以将第一个查询的结果加载到数组中-memory,然后循环遍历第二个查询结果,并针对第一个查询结果逐个检查它们,如果它们存在则删除它们。

我不确定实际上会有更好的表现(取决于很多事情)。您可能还想考虑使用NOT EXISTS并检查性能,即

SELECT  RTRIM(LTRIM(A.HEAD)),
  A.EFFECTIVE_DATE,
FROM   TABLE_1 A
WHERE  A.TYPE_OF_ACTION='6'
AND    A.EFFECTIVE_DATE >= ADD_MONTHS(SYSDATE,-15)  
AND NOT EXISTS (
  SELECT 1 fFROM TABLE_2 B
  WHERE RTRIM(LTRIM(A.HEAD)) = RTRIM(LTRIM(B.HEAD))
  AND A.EFFECTIVE_DATE = B.EFFECTIVE_DATE
)

RTRIM(LTRIM(A.HEAD))

也可能需要一些功能索引