I only have access to oracle standard edition, which feature of oracle standard edition provides the functionality like that of partitioning is there any concept of logically me
Handmade Partitioning
- a working example for Oracle XE/SECreate a row type and tables for partitions.
create type DOCS_ROW_TYPE as object (
doc_id NUMBER,
doc_name VARCHAR2(100),
doc_date DATE
);
-- Create partition YOLD table (data from OLD years)
create table DOCS_YOLD OF DOCS_ROW_TYPE;
alter table DOCS_YOLD modify doc_id not null;
alter table DOCS_YOLD modify doc_date not null;
-- Create primary key
alter table DOCS_YOLD add constraint DOCS_YOLD_PK primary key (DOC_ID) using index;
-- Create indexes
create index DOCS_YOLD_DATE_IDX on DOCS_YOLD (DOC_DATE);
create index DOCS_YOLD_NAME_UPCASE_IDX on DOCS_YOLD (UPPER(DOC_NAME));
-- Create partition Y2014 table (data from 2014 years)
create table DOCS_Y2014 OF DOCS_ROW_TYPE;
alter table DOCS_Y2014 modify doc_id not null;
alter table DOCS_Y2014 modify doc_date not null;
-- Create primary key
alter table DOCS_Y2014 add constraint DOCS_Y2014_PK primary key (DOC_ID) using index;
-- Create indexes
create index DOCS_Y2014_DATE_IDX on DOCS_Y2014 (DOC_DATE);
create index DOCS_Y2014_NAME_UPCASE_IDX on DOCS_Y2014 (UPPER(DOC_NAME));
-- Create partition Y2015 table (data from 2015 years)
create table DOCS_Y2015 OF DOCS_ROW_TYPE;
alter table DOCS_Y2015 modify doc_id not null;
alter table DOCS_Y2015 modify doc_date not null;
-- Create primary key
alter table DOCS_Y2015 add constraint DOCS_Y2015_PK primary key (DOC_ID) using index;
-- Create indexes
create index DOCS_Y2015_DATE_IDX on DOCS_Y2015 (DOC_DATE);
create index DOCS_Y2015_NAME_UPCASE_IDX on DOCS_Y2015 (UPPER(DOC_NAME));
-- Create partition Y2016 table (data from 2016 years)
create table DOCS_Y2016 OF DOCS_ROW_TYPE;
alter table DOCS_Y2016 modify doc_id not null;
alter table DOCS_Y2016 modify doc_date not null;
-- Create primary key
alter table DOCS_Y2016 add constraint DOCS_Y2016_PK primary key (DOC_ID) using index;
-- Create indexes
create index DOCS_Y2016_DATE_IDX on DOCS_Y2016 (DOC_DATE);
create index DOCS_Y2016_NAME_UPCASE_IDX on DOCS_Y2016 (UPPER(DOC_NAME));
-- Create partition YNEW table (data from NEW years)
create table DOCS_YNEW OF DOCS_ROW_TYPE;
alter table DOCS_YNEW modify doc_id not null;
alter table DOCS_YNEW modify doc_date not null;
-- Create primary key
alter table DOCS_YNEW add constraint DOCS_YNEW_PK primary key (DOC_ID) using index;
-- Create indexes
create index DOCS_YNEW_DATE_IDX on DOCS_YNEW (DOC_DATE);
create index DOCS_YNEW_NAME_UPCASE_IDX on DOCS_YNEW (UPPER(DOC_NAME));
You have to define correct constraints then Oracle will use filters in query execution plan!
alter table DOCS_YOLD
add constraint DOCS_YOLD_KEY_CHECK
check (DOC_DATE < to_date('2014-01-01','yyyy-mm-dd'));
alter table DOCS_Y2014
add constraint DOCS_Y2014_KEY_CHECK
check (DOC_DATE >= to_date('2014-01-01','yyyy-mm-dd') and DOC_DATE < to_date('2015-01-01','yyyy-mm-dd'));
alter table DOCS_Y2015
add constraint DOCS_Y2015_KEY_CHECK
check (DOC_DATE >= to_date('2015-01-01','yyyy-mm-dd') and DOC_DATE < to_date('2016-01-01','yyyy-mm-dd'));
alter table DOCS_Y2016
add constraint DOCS_Y2016_KEY_CHECK
check (DOC_DATE >= to_date('2016-01-01','yyyy-mm-dd') and DOC_DATE < to_date('2017-01-01','yyyy-mm-dd'));
alter table DOCS_YNEW
add constraint DOCS_YNEW_KEY_CHECK
check (DOC_DATE >= to_date('2017-01-01','yyyy-mm-dd'));
Create a view DOCS_PARTITIONS as all partitions union
create or replace view docs_partitions as
select * from docs_yold
union all
select * from docs_y2014
union all
select * from docs_y2015
union all
select * from docs_y2016
union all
select * from docs_ynew
Create a PK sequence
create sequence DOCS_MASTER_PK_SEQ
minvalue 1
maxvalue 1000000000
start with 1
increment by 1
cache 10;
Create a "INSTEAD OF" trigger on the DOCS_PARTITIONS view to redistributing data
create or replace trigger docs_partitions_insert
INSTEAD OF insert on docs_partitions
for each row
declare
v_year number(4);
v_doc_id docs_partitions.DOC_ID%type;
begin
v_doc_id := docs_master_pk_seq.nextval;
v_year := to_number(to_char(:new.doc_date,'yyyy'));
if (v_year < 2014) then
insert into docs_yold (doc_id, doc_name, doc_date)
values (v_doc_id, :new.doc_name, :new.doc_date);
elsif (v_year = 2014) then
insert into docs_y2014 (doc_id, doc_name, doc_date)
values (v_doc_id, :new.doc_name, :new.doc_date);
elsif (v_year = 2015) then
insert into docs_y2015 (doc_id, doc_name, doc_date)
values (v_doc_id, :new.doc_name, :new.doc_date);
elsif (v_year = 2016) then
insert into docs_y2016 (doc_id, doc_name, doc_date)
values (v_doc_id, :new.doc_name, :new.doc_date);
else
insert into docs_ynew (doc_id, doc_name, doc_date)
values (v_doc_id, :new.doc_name, :new.doc_date);
end if;
end docs_partitions_insert;
You can also distributing data via a master table - DOCS_MASTER
-- Create partition MASTER table (all data)
create table DOCS_MASTER OF DOCS_ROW_TYPE;
alter table DOCS_MASTER modify doc_id not null;
alter table DOCS_MASTER modify doc_date not null;
-- Create primary key
alter table DOCS_MASTER add constraint DOCS_MASTER_PK primary key (DOC_ID) using index;
-- Create indexes
create index DOCS_MASTER_DATE_IDX on DOCS_MASTER (DOC_DATE);
create index DOCS_MASTER_NAME_UPCASE_IDX on DOCS_MASTER (UPPER(DOC_NAME));
Create a trigger on the DOCS_MASTER table to redistributing data
create or replace trigger docs_master_insert
before insert on docs_master
for each row
declare
v_year number(4);
begin
:new.doc_id := docs_master_pk_seq.nextval;
v_year := to_number(to_char(:new.doc_date,'yyyy'));
if (v_year < 2014) then
insert into docs_yold (doc_id, doc_name, doc_date)
values (:new.doc_id, :new.doc_name, :new.doc_date);
elsif (v_year = 2014) then
insert into docs_y2014 (doc_id, doc_name, doc_date)
values (:new.doc_id, :new.doc_name, :new.doc_date);
elsif (v_year = 2015) then
insert into docs_y2015 (doc_id, doc_name, doc_date)
values (:new.doc_id, :new.doc_name, :new.doc_date);
elsif (v_year = 2016) then
insert into docs_y2016 (doc_id, doc_name, doc_date)
values (:new.doc_id, :new.doc_name, :new.doc_date);
else
insert into docs_ynew (doc_id, doc_name, doc_date)
values (:new.doc_id, :new.doc_name, :new.doc_date);
end if;
end docs_master_insert;
Generate data for test
declare
v_i integer;
v_count integer := 1000000;
begin
-- insert docs through the master table
for v_i in 1..v_count
loop
insert into docs_master (doc_name, doc_date)
values (
'DOC-M-'||v_i,
to_date(trunc(DBMS_RANDOM.VALUE(to_char(TO_DATE('2000-01-01','yyyy-mm-dd'),'J'),to_char(TO_DATE('2100-01-01','yyyy-mm-dd'),'J'))),'J')
);
if mod(v_i,10000)=0 then
commit;
dbms_output.put_line('rows M inserted: '||v_i||', '||(round(100*v_i/v_count))||'%');
end if;
end loop;
commit;
-- insert docs through the partitions view
/*
for v_i in 1..2
loop
insert into docs_partitions (doc_name, doc_date)
values (
'DOC-P-'||v_i,
to_date(trunc(DBMS_RANDOM.VALUE(to_char(TO_DATE('2000-01-01','yyyy-mm-dd'),'J'),to_char(TO_DATE('2100-01-01','yyyy-mm-dd'),'J'))),'J')
);
if mod(v_i,1000)=0 then
commit;
dbms_output.put_line('rows P inserted: '||v_i);
end if;
end loop;
commit;
*/
end;
Select data from the DOCS_PARTITIONS view
select dp.*
from DOCS_PARTITIONS dp
where
dp.DOC_DATE between to_date('2014-02','yyyy-mm') and to_date('2014-03','yyyy-mm')
-- SQL execution plan with filters!!!
SELECT STATEMENT, GOAL = ALL_ROWS 0 1 78
VIEW PART_TEST DOCS_PARTITIONS 0 1 78
UNION-ALL
FILTER
TABLE ACCESS BY INDEX ROWID PART_TEST DOCS_YOLD 3 11 814
INDEX RANGE SCAN PART_TEST DOCS_YOLD_DATE_IDX 3 833
TABLE ACCESS BY INDEX ROWID PART_TEST DOCS_Y2014 1 750 55500
INDEX RANGE SCAN PART_TEST DOCS_Y2014_DATE_IDX 1 45
FILTER
TABLE ACCESS BY INDEX ROWID PART_TEST DOCS_Y2015 1 1 74
INDEX RANGE SCAN PART_TEST DOCS_Y2015_DATE_IDX 1 44
FILTER
TABLE ACCESS BY INDEX ROWID PART_TEST DOCS_Y2016 1 1 74
INDEX RANGE SCAN PART_TEST DOCS_Y2016_DATE_IDX 1 47
FILTER
TABLE ACCESS BY INDEX ROWID PART_TEST DOCS_YNEW 14 61 4514
INDEX RANGE SCAN PART_TEST DOCS_YNEW_DATE_IDX 14 5565