【问题标题】:Oracle SQL pull data for a selected date from a table that is daily partitionedOracle SQL 从每日分区的表中提取选定日期的数据
【发布时间】:2015-04-10 05:02:06
【问题描述】:

我喜欢做的是仅在每个星期五的繁忙时间提取一个数据集,为期 1 年。 我使用了以下查询:

select to_char(datetimelocal,'DD/MM/YYYY HH24:MI:SS'), colA,colB,colC,colD 
from Schema_X.Table_Y
where DATETIMELOCAL between '1-Apr-2014' and '1-Apr-2015' 
    and to_char(datetimelocal,'D')=6  
    and to_number(to_char(datetimelocal,'sssss')) between 57600 and 64800

此查询有效,但我从系统管理员那里收到以下警告消息,提示我已用尽系统资源。

“有一个用户 xxx 对 Schema_X 表运行查询,这些表正在扫描整个表而不是进行分区修剪。所以用户应该使用分区字段也减少日期范围,这太大了”

我发现 Table_X 是每日分区的,但不知道如何明智地使用分区来减少系统负载。

分区是这样的:

PARTITION_NAME,HIGH_VALUE,HIGH_VALUE_LENGTH,TABLESPACE_NAME,COMPRESSION,NUM_ROWS,BLOCKS,EMPTY_BLOCKS,LAST_ANALYZED,AVG_SPACE,SUBPARTITION_COUNT
20121230,TO_DATE(' 2012-12-31 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'),83,NATIONAL_RPT,DISABLED,,,,,,0
20121231,TO_DATE(' 2013-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'),83,NATIONAL_RPT,DISABLED,,,,,,0
20130101,TO_DATE(' 2013-01-02 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'),83,NATIONAL_RPT,DISABLED,,,,,,0
20130102,TO_DATE(' 2013-01-03 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'),83,NATIONAL_RPT,DISABLED,,,,,,0
20130103,TO_DATE(' 2013-01-04 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'),83,NATIONAL_RPT,DISABLED,,,,,,0
....

【问题讨论】:

    标签: sql oracle overloading partition


    【解决方案1】:

    正如 Jon 所说,由于 where 子句的表达方式,Oracle 无法放大到特定分区。如果你想要所有星期五,你必须给 sql 引擎特定的日子。这可以通过创建一个包含您需要的所有星期五的表格或即时生成一个表格来完成。

    -- generate table
    CREATE TABLE friday_table (friday_date DATE);
    
    DECLARE
      v_last_friday_of_period DATE := to_date('2015.04.10','yyyy.mm.dd');
      v_particular_friday DATE := v_last_friday_of_period;
    BEGIN
      WHILE v_last_friday_of_period - v_particular_friday < 365 LOOP
        INSERT INTO friday_table VALUES (v_particular_friday);
        v_particular_friday := v_particular_friday - 7;
      END LOOP;
    END;
    /
    
    SELECT *
    FROM tbl t
        ,friday_table f
    WHERE t.datetimelock BETWEEN to_date(to_char(f.friday_date,'yyyy.mm.dd ')||'12:00:00','yyyy.mm.dd hh24:mi:ss') 
                             AND to_date(to_char(f.friday_date,'yyyy.mm.dd ')||'13:00:00','yyyy.mm.dd hh24:mi:ss');
    
    -- on the fly
    SELECT *
    FROM tbl t
        ,(SELECT to_date('2015.04.10','yyyy.mm.dd') - rownum * 7 AS friday_date
          FROM dual
          CONNECT BY rownum <= 52) f
    WHERE t.datetimelock BETWEEN to_date(to_char(f.friday_date,'yyyy.mm.dd ')||'12:00:00','yyyy.mm.dd hh24:mi:ss') 
                             AND to_date(to_char(f.friday_date,'yyyy.mm.dd ')||'13:00:00','yyyy.mm.dd hh24:mi:ss');
    

    【讨论】:

      【解决方案2】:

      您的查询分阶段过滤,首先是按年,然后是按天,然后是按时间。这意味着原则上任何记录都可以计算在内;系统无法轻易放大您需要的分区。您需要根据具体日期来表达过滤器:

      SELECT *
      FROM Tbl
      WHERE
              DateTimeLock >= DATE'2015-04-03' AND DateTimeLock < DATE'2015-04-04' AND 
          AND EXTRACT(HOUR FROM DateTimeLock)) BETWEEN 16 AND 17  -- Inclusive
      

      这将放大您需要的确切分区。

      但是,它显然只是为您提供一天的数据。您可能需要使用循环在每个星期五在单独的查询中进行查询,将结果收集到一个表中。

      您可以尝试通过在第一个 DateTimeLock 过滤器中使用 OR 将其保留为单个查询:

      (
         DateTimeLock >= DATE'2015-04-03' AND DateTimeLock < DATE'2015-04-04'
      OR DateTimeLock >= DATE'2015-03-27' AND DateTimeLock < DATE'2015-03-28'
      OR DateTimeLock >= DATE'2015-03-20' AND DateTimeLock < DATE'2015-03-21'
      )
      AND EXTRACT(HOUR FROM DateTimeLock)) BETWEEN 16 AND 17  -- Inclusive
      

      ...但是,我怀疑查询引擎会将其转换为表扫描,这就是您开始使用的。

      【讨论】:

        【解决方案3】:

        我认为理想情况下,您应该编写一个查询来生成您想要运行查询的日期列表。

        类似...

        (select <somedate_that_is_a_friday> + rownum * 7
        from   dual
        connect by level <= <however_many_you_want>)
        

        如果你那时:

        select ...
        where  DATETIMELOCAL in (select <somedate_that_is_a_friday> + ... etc
        

        ...那么解释计划应该显示分区正在由 KEY 选择,这表明分区修剪将发生,但优化器直到执行时才知道将访问哪些分区。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-06-16
          • 1970-01-01
          • 1970-01-01
          • 2022-01-17
          • 2014-12-30
          • 1970-01-01
          • 2013-05-08
          相关资源
          最近更新 更多