繁体   English   中英

Oracle SQL从每日分区的表中提取选定日期的数据

[英]Oracle SQL pull data for a selected date from a table that is daily partitioned

我想做的是在一年的每个星期五仅在繁忙时段提取数据集。 我使用以下查询:

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
....

您的查询分阶段进行过滤,首先是按年份,然后是按天,然后是时间。 这意味着原则上可以记录任何记录; 系统无法轻松放大所需的分区。 您需要根据特定日期来表示过滤器:

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

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

正如乔恩所说,由于无法表达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');

我认为理想情况下,您将编写查询以生成要运行查询的日期列表。

就像是 ...

(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正在选择分区,这表明将进行分区修剪,但是优化器直到执行时才知道将访问哪些分区。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM