Oracle中用于动态日期加入的性能调优

时间:2016-05-10 03:23:28

标签: oracle oracle11g

我有一个场景,我必须在24小时内动态聚合数据。

例如:如果用户选择FROM日期为2016年1月5日上午8:00,而日期为2016年1月10日上午2:00,则输出中的数据应汇总自2016年1月5日上午8:00至1月06日2016年7:59 AM为1天(2016年1月5日)。

Jan 5 2016 - Jan 5 2016 8:00 AM to Jan 6 2016 7:59 AM
Jan 6 2016 - Jan 6 2016 8:00 AM to Jan 7 2016 7:59 AM
Jan 7 2016 - Jan 7 2016 8:00 AM to Jan 8 2016 7:59 AM
Jan 8 2016 - Jan 8 2016 8:00 AM to Jan 9 2016 7:59 AM
Jan 9 2016 - Jan 9 2016 8:00 AM to Jan 10 2016 2:00 AM

为实现这一目标,我从事实表中的日期列中减去了8小时,并将其加入日期维度。查询如下所示:

SELECT D.DAY_FMT,SUM(F.MEASURE) from FACT F
INNER JOIN DATES D ON 
to_number(to_char((F.DATESTIME - 0.3333333),'YYYYMMDD')) = D.DATEID
WHERE F.DATESTIME between to_timestamp ('05-Jan-16 08.00.00.000000000 AM') 
and  to_timestamp ('10-Jan-16 02.00.00.000000000 AM')
GROUP BY D.DAY_FMT

注1:如果发件人时间 06:00 ,那么我们将减去 0.25 (天)而不是 0.3333333 (天) )

注2:Fact表有数十亿行。

有没有办法改善上述查询的性能?

1 个答案:

答案 0 :(得分:0)

在Oracle中,日期和时间存储在一起。你不需要加入平等,你不需要在任何职能中包装日期。 (以及时间戳的原因?)在"右侧"进行所有计算(如果有的话)。条件意味着计算只进行一次,每行都相同,而不是每行分别进行。

select   f.day_fmt, sum(f.measure) as some_col_name 
from     fact f inner join dates d 
             on f.datestime >= to_date('05-Jan-16 08:00:00 AM', 'dd-Mon-yy hh:mi:ss AM') 
            and f.datestime <  to_date('10-Jan-16 02:00:00 AM', 'dd-Mon-yy hh:mi:ss AM')
group by day_fmt;

编辑:根据OP的进一步说明 - 假设数据在表格中,事实&#34; - 使用列day_fmt,measure和datestime。分配是聚合(总和)度量,按day_fmt分组,并且还按24小时间隔分组,从用户选择的日期时间开始,以用户选择的日期时间结束。解决方法如下

with user_input (sd, ed) as (
            select to_date('05-Jan-16 08:00:00 AM', 'dd-Mon-yy hh:mi:ss AM'),
                   to_date('10-Jan-16 02:00:00 AM', 'dd-Mon-yy hh:mi:ss AM') from dual
         ),
     prep (dt) as (
            select (select sd from user_input) + level - 1 from dual
            connect by level < (select ed - sd from user_input) + 1
            union
            select ed from user_input
         ),
     dates (from_date, to_date) as (
            select dt, lead(dt) over (order by dt) from prep
         )
select   f.day_fmt, d.from_datetime, d.to_datetime, sum(f.measure) as some_column_name
from     fact f inner join dates d
                on f.datestime >= d.from_datetime and f.datestime < d.to_datetime
where    to_datetime is not null
group by f.day_fmt, d.from_datetime, f.to_datetime
order by f.day_fmt, d.from_datetime;

通过不使用f.datestime周围的函数调用,您可以利用在&#34;事实&#34;的这一列上定义的索引。 table(您已经拥有的索引或您现在可以创建的索引,以帮助加快查询速度)。