如何使用行发生器避免昂贵的笛卡尔积

时间:2014-02-18 16:15:50

标签: oracle cartesian-product date-manipulation

我正在开发一个执行大量日期操作的查询(Oracle 11g)。使用行生成器,我正在检查另一个表中每个记录的日期范围内的每个日期。通过另一个查询,我知道我的行生成器需要生成8500个日期,这个数量每年将增加365天。此外,我正在检查的表有大约18000条记录,这个表预计每年会增长数千条记录。

将行生成器连接到另一个表以获取每个记录的日期范围时出现问题。 SQLTuning Advisor说有一个昂贵的笛卡尔产品,这是有道理的,因为查询当前可以生成多达8500 x 18000条记录。这是查询的精简版,没有所有日期逻辑等。

with n as (
  select level n
  from dual 
  connect by level <= 8500
 )
select t.id, t.origdate + n origdate    
from (
    select id, origdate, closeddate
    from my_table
) t
join n on origdate + n - 1 <= closeddate -- here's the problem join
order by t.id, t.origdate;

是否有另一种方法可以在没有笛卡尔积的情况下连接这两个表?

我需要计算每个记录的经过时间,不允许周末和联邦假期,以便我可以对经过的时间进行排序。此外,表的分页是在服务器端完成的,因此我们不能只加载到表中并对客户端进行排序。

系统中记录的最大年龄现在是3656天,平均值是560,所以它不如8500 x 18000差;但它仍然很糟糕。

我只是想让自己添加一个字段来存储开头,计算一次并存储已用时间,并创建一个计划任务来每晚更新所有打开的记录。

1 个答案:

答案 0 :(得分:0)

如果您稍微重写连接条件,我认为您会获得更好的性能:

with n as (
  select level n
  from dual 
  connect by level <= 8500
 )
select t.id, t.origdate + n origdate    
from (
    select id, origdate, closeddate
    from my_table
) t
join n on Closeddate - Origdate + 1 <= n --you could even create a function-based index
order by t.id, t.origdate;