Oracle 有一个包含活动周期的合同表,如何计算每日活动合同计数?

Oracle 有一个包含活动周期的合同表,如何计算每日活动合同计数?,oracle,optimization,common-table-expression,Oracle,Optimization,Common Table Expression,我有两张桌子: 合同(…,d1日期,d2日期,…)描述了一些合同并包含数百万(n*10^6!!!)行,d1和d2是相应的合同开始和终止日期 日历(d日期)包含连续日期列表(这样的表格对于不同的用途非常有用) 我需要为日历的每一行计算活动合同的数量,假设如果contract.d1你的方法很好,那么该合同是活动的,我认为没有更好的根本解决方案。 要想获得所有的合同交易,你必须至少考虑两次在合同表中的记录,你正在做。< /P> 一种微妙的不同的可能性是,不必对表进行双重扫描,而是执行一次扫描,并与

我有两张桌子:

  • 合同(…,d1日期,d2日期,…)
    描述了一些合同并包含数百万(n*10^6!!!)行,
    d1
    d2
    是相应的合同开始和终止日期
  • 日历(d日期)
    包含连续日期列表(这样的表格对于不同的用途非常有用)

我需要为
日历
的每一行计算活动合同的数量,假设如果
contract.d1你的方法很好,那么该合同是活动的,我认为没有更好的根本解决方案。
要想获得所有的合同交易,你必须至少考虑两次在合同表中的记录,你正在做。< /P>
一种微妙的不同的可能性是,不必对表进行双重扫描,而是执行一次扫描,并与包含激活和终止记录的两个记录表连接

with two as (
select 1 n from dual union all
select -1 n from dual),
contract_transactions as (
select 
case when n = 1 then c.d1 else c.d2+1 end as d,
n
from contract c
cross join two d)
select d, sum(n) n 
from contract_transactions
group by d
而不是您的双
全表扫描

----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |  1528K|    13M|   107K  (1)| 00:25:06 |
|   1 |  UNION-ALL                  |          |       |       |            |          |
|   2 |   HASH GROUP BY             |          |   764K|  6715K| 53785   (1)| 00:12:33 |
|   3 |    TABLE ACCESS STORAGE FULL| CONTRACT |   764K|  6715K| 53767   (1)| 00:12:33 |
|   4 |   HASH GROUP BY             |          |   764K|  6715K| 53785   (1)| 00:12:33 |
|   5 |    TABLE ACCESS STORAGE FULL| CONTRACT |   764K|  6715K| 53767   (1)| 00:12:33 |
----------------------------------------------------------------------------------------
只有一次
全表扫描
,但随后是两个记录表的联接

-----------------------------------------------------------------------------------------
| Id  | Operation                    | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |          |  1528K|    30M|   107K  (1)| 00:25:07 |
|   1 |  HASH GROUP BY               |          |  1528K|    30M|   107K  (1)| 00:25:07 |
|   2 |   MERGE JOIN CARTESIAN       |          |  1528K|    30M|   107K  (1)| 00:25:06 |
|   3 |    VIEW                      |          |     2 |     6 |     4   (0)| 00:00:01 |
|   4 |     UNION-ALL                |          |       |       |            |          |
|   5 |      FAST DUAL               |          |     1 |       |     2   (0)| 00:00:01 |
|   6 |      FAST DUAL               |          |     1 |       |     2   (0)| 00:00:01 |
|   7 |    BUFFER SORT               |          |   764K|    13M|   107K  (1)| 00:25:07 |
|   8 |     TABLE ACCESS STORAGE FULL| CONTRACT |   764K|    13M| 53767   (1)| 00:12:33 |
-----------------------------------------------------------------------------------------
我不认为会有相关的性能差异(相同的选项是CBO;)


对我来说,使用联接将
合同
记录拆分为两个事务更为自然。

我测量了这些查询测试数据的时间,第一个面超过1秒,最后大约100ms。基本问题-1秒的时间真的不令人满意吗?多久执行一次此查询?每秒100次?每分钟一次?一天一次,或者一个月一次?是否值得花时间扩展此查询,并使其变得越来越复杂,以便客户端每天只进行一次查询,并且该查询将持续100毫秒而不是2秒?更复杂=将来更难维护。一些新的程序员在两年内将很难理解这个问题。在生产数据库上,这是几分钟vs 5秒,所以它确实值得改进。但要明确的是,没有人会运行这个查询,因为我开发它只是为了满足自己的好奇心;)谢谢你的想法,使用连接对我来说也更准确。
with 
    events_agg (d,n) as (
        select d1,    count(*) from contract  group by d1 -- new contracts
        union all
        select d2+1, -count(*) from contract group by d2 -- term. contracts
    ),
    counts_daily(d,n) as (
        select  d, sum(n)
        from    events_agg  
        group   by d
    ),
    counts_running(d,n) as (
        select  d, sum(n) over (order by d)
        from    counts_daily
        order by d
    )
select  d, 
        nvl(n, lag(n ignore nulls) over(order by d)) n  
from    calendar 
left    join counts_running using(d)    
order   by d;
with 
    --- TEST DATA EMULATION ---
    params as (
        select  trunc(sysdate) - 100  d0,                
                1e5                   number_of_contracts,
                100                   max_contract_term 
        from dual
    ),
    start_dates (d1) as(
        select  trunc(d0 + dbms_random.value(0, sysdate-d0)) d1 
                from params connect by level <= number_of_contracts
    ),
    contract (d1, d2) as ( 
        select  d1, 
                trunc(d1 + dbms_random.value(0, max_contract_term)) d2
        from    start_dates, params       
    ),
    calendar (d) as (
        select  d0 + level - 1 
        from    params
        connect by level <= sysdate - d0 + 1  
    ),
    --- END OF TEST DATA ---
    ------------------------
    ...
with two as (
select 1 n from dual union all
select -1 n from dual),
contract_transactions as (
select 
case when n = 1 then c.d1 else c.d2+1 end as d,
n
from contract c
cross join two d)
select d, sum(n) n 
from contract_transactions
group by d
----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |  1528K|    13M|   107K  (1)| 00:25:06 |
|   1 |  UNION-ALL                  |          |       |       |            |          |
|   2 |   HASH GROUP BY             |          |   764K|  6715K| 53785   (1)| 00:12:33 |
|   3 |    TABLE ACCESS STORAGE FULL| CONTRACT |   764K|  6715K| 53767   (1)| 00:12:33 |
|   4 |   HASH GROUP BY             |          |   764K|  6715K| 53785   (1)| 00:12:33 |
|   5 |    TABLE ACCESS STORAGE FULL| CONTRACT |   764K|  6715K| 53767   (1)| 00:12:33 |
----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
| Id  | Operation                    | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |          |  1528K|    30M|   107K  (1)| 00:25:07 |
|   1 |  HASH GROUP BY               |          |  1528K|    30M|   107K  (1)| 00:25:07 |
|   2 |   MERGE JOIN CARTESIAN       |          |  1528K|    30M|   107K  (1)| 00:25:06 |
|   3 |    VIEW                      |          |     2 |     6 |     4   (0)| 00:00:01 |
|   4 |     UNION-ALL                |          |       |       |            |          |
|   5 |      FAST DUAL               |          |     1 |       |     2   (0)| 00:00:01 |
|   6 |      FAST DUAL               |          |     1 |       |     2   (0)| 00:00:01 |
|   7 |    BUFFER SORT               |          |   764K|    13M|   107K  (1)| 00:25:07 |
|   8 |     TABLE ACCESS STORAGE FULL| CONTRACT |   764K|    13M| 53767   (1)| 00:12:33 |
-----------------------------------------------------------------------------------------