我喜欢做的是在每个星期五的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表上运行查询,这些用户正在扫描整个表而不进行分区修剪。所以用户应该使用分区字段也减少日期范围,这太大了#34;
我发现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
....
答案 0 :(得分: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
...但是,我怀疑查询引擎会将其转换为表格扫描,这就是你开始使用的。
答案 1 :(得分:2)
正如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 :(得分:1)
我认为理想情况下,您可以编写查询来生成要运行查询的日期列表。
像...一样的东西。
(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正在选择分区,这表示将进行分区修剪,但优化器不知道在执行时间之前将访问哪些分区。