We intend working with ONE table only. DROP it for now. We build it entirely here.
drop table events purge;
ORA-00942: table or view does not existMore Details: https://docs.oracle.com/error-help/db/ora-00942
Create an empty, non-partitionioned table having a generated IDENTITY
create table events
( event_id integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL PRIMARY KEY,
event_date date not null,
sensor_id integer not null,
reading_uom varchar2(32) not null,
reading_val varchar2(32) not null )
Table created.
1st seeding data for ONE DATE and TWENTY sensors
insert into events ( event_date, sensor_id, reading_uom, reading_val )
SELECT to_date ('19981215','YYYYMMDD'),
rownum,
'Ampere',
round( dbms_random.value(1,1000), 6 )
FROM dual CONNECT BY LEVEL <= 20
2nd seeding data for VARIOUS RANDOM DATES up to TWELVE years span
insert into events ( event_date, sensor_id, reading_uom, reading_val )
SELECT to_date ('19981215','YYYYMMDD') + round( dbms_random.value(1, 12 * 365 ), 4 ),
sensor_id,
reading_uom,
round( dbms_random.value(1,1000), 6 )
FROM events,
( select 'something' FROM dual CONNECT BY LEVEL <= 9 )
3rd seeding data for VARIOUS RANDOM DATES up to FIVE years span
insert into events ( event_date, sensor_id, reading_uom, reading_val )
SELECT to_date ('19981215','YYYYMMDD') + 12 * 365 + round( dbms_random.value(1, 5 * 365 ), 6 ),
sensor_id,
reading_uom,
round( dbms_random.value(1,1000), 6 )
FROM events,
( select 'something' FROM dual CONNECT BY LEVEL <= 10 )
Change NON-PARTITIONED table to RANGE PARTITIONED table ONLINE including INDEX maintenance
alter table events modify
partition by range ( event_date )
(PARTITION observations_PAST VALUES LESS THAN (TO_DATE('20000101','YYYYMMDD')),
PARTITION observations_CY_2000 VALUES LESS THAN (TO_DATE('20010101','YYYYMMDD')),
PARTITION observations_CY_2001 VALUES LESS THAN (TO_DATE('20020101','YYYYMMDD')),
PARTITION observations_CY_2002 VALUES LESS THAN (TO_DATE('20030101','YYYYMMDD')),
PARTITION observations_CY_2003 VALUES LESS THAN (TO_DATE('20040101','YYYYMMDD')),
PARTITION observations_CY_2004 VALUES LESS THAN (TO_DATE('20050101','YYYYMMDD')),
PARTITION observations_CY_2005 VALUES LESS THAN (TO_DATE('20060101','YYYYMMDD')),
PARTITION observations_CY_2006 VALUES LESS THAN (TO_DATE('20070101','YYYYMMDD')),
PARTITION observations_CY_2007 VALUES LESS THAN (TO_DATE('20080101','YYYYMMDD')),
PARTITION observations_CY_2008 VALUES LESS THAN (TO_DATE('20090101','YYYYMMDD')),
PARTITION observations_CY_2009 VALUES LESS THAN (TO_DATE('20100101','YYYYMMDD')),
PARTITION observations_CY_2010 VALUES LESS THAN (TO_DATE('20110101','YYYYMMDD')),
PARTITION observations_CY_2011 VALUES LESS THAN (TO_DATE('20120101','YYYYMMDD')),
PARTITION observations_CY_2012 VALUES LESS THAN (TO_DATE('20130101','YYYYMMDD')),
PARTITION observations_CY_2013 VALUES LESS THAN (TO_DATE('20140101','YYYYMMDD')),
PARTITION observations_CY_2014 VALUES LESS THAN (TO_DATE('20150101','YYYYMMDD')),
PARTITION observations_CY_2015 VALUES LESS THAN (TO_DATE('20160101','YYYYMMDD')),
PARTITION observations_CY_2016 VALUES LESS THAN (TO_DATE('20170101','YYYYMMDD')),
PARTITION observations_CY_2017 VALUES LESS THAN (TO_DATE('20180101','YYYYMMDD')),
PARTITION observations_CY_2018 VALUES LESS THAN (TO_DATE('20190101','YYYYMMDD')),
PARTITION observations_FUTURE VALUES LESS THAN ( MAXVALUE )
) ONLINE
UPDATE INDEXES;
Simple query - obtain earliest and last year
select sensor_id,
to_char( min(event_date), 'YYYY') earliest_year,
to_char( max(event_date), 'YYYY') latest_year
from events
group by cube(sensor_id);
4th seeding data for VARIOUS RANDOM DATES up to FIVE years span
insert into events ( event_date, sensor_id, reading_uom, reading_val )
SELECT to_date ('19981215','YYYYMMDD') + 19 * 365 + round( dbms_random.value(1, 5 * 365 ), 6 ),
sensor_id,
reading_uom,
round( dbms_random.value(1,1000), 6 )
FROM events,
( select 'something' FROM dual CONNECT BY LEVEL <= 10 )
1st time statistics gathering - the entire table
execute DBMS_STATS.GATHER_TABLE_STATS( null, tabname => 'events')
Provide basic information about the TABLE and PARTITIONS
select partition_name, subpartition_count, num_rows
from user_tab_partitions
order by partition_position
We have all this FUTURE dated events. Just an overview to identify the need for partition splitting
select sensor_id,
to_char( min(event_date), 'YYYY') earliest_year,
to_char( max(event_date), 'YYYY') latest_year,
count(*) readings_in_year,
count( distinct to_char( event_date, 'YYYYMMDD' ) ) days_having_readings,
count( distinct to_char( event_date, 'HH24' ) ) hours_having_readings
from events partition ( observations_future )
group by cube(sensor_id)
order by sensor_id
Split the partition for FUTURE data into several ones in one step.
ALTER TABLE events SPLIT PARTITION observations_future INTO
(PARTITION observations_CY_2019 VALUES LESS THAN ( to_date( '20200101', 'YYYYMMDD')),
PARTITION observations_CY_2020 VALUES LESS THAN ( to_date( '20210101', 'YYYYMMDD')),
PARTITION observations_CY_2021 VALUES LESS THAN ( to_date( '20220101', 'YYYYMMDD')),
PARTITION observations_CY_2022 VALUES LESS THAN ( to_date( '20230101', 'YYYYMMDD')),
PARTITION observations_FUTURE
) ONLINE;
Produce OPTIMIZER STATISTICS for the NEWLY splitted partitions - show the results
execute DBMS_STATS.GATHER_TABLE_STATS( null, tabname => 'events', partname => 'observations_cy_2019');
execute DBMS_STATS.GATHER_TABLE_STATS( null, tabname => 'events', partname => 'observations_cy_2020');
execute DBMS_STATS.GATHER_TABLE_STATS( null, tabname => 'events', partname => 'observations_cy_2021');
execute DBMS_STATS.GATHER_TABLE_STATS( null, tabname => 'events', partname => 'observations_cy_2022');
execute DBMS_STATS.GATHER_TABLE_STATS( null, tabname => 'events', partname => 'observations_future');
Query OPTIMIZER STATISTICS for ALL partitions - show the results
select partition_name, subpartition_count, num_rows
from user_tab_partitions
order by partition_position
Just another simple query - trick question: is the predicate on EVENT_DATE clever?
select sensor_id,
to_char( min(event_date), 'YYYYMMDD') earliest_day,
to_char( max(event_date), 'YYYYMMDD') latest_day,
count(*) readings_in_month,
count( distinct to_char( event_date, 'YYYYMMDD' ) ) days_having_readings,
count( distinct to_char( event_date, 'HH24' ) ) hours_having_readings
from events
where to_char( event_date, 'YYYYMM' ) = '201807'
group by cube(sensor_id)
order by sensor_id
Add virtual columns CALENDAR_YEAR and THE_HOUR - make it look nicer with virtual columns
alter table events add cal_year as ( to_number( to_char( event_date, 'YYYY' )));
alter table events add cal_hour as ( to_number( to_char( event_date, 'HH24' )));
Thank you
select 'That is all folks' from dual;