问题
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 merging table like that in MYSQL.
回答1:
Only thing that comes to mind is to have a real table for each 'partition', and then a view than unions them all together. But you'd have to rebuild the view every time you added or removed a 'partition', and there might be performance issues, as well as potential complication with anything except selects - which you could get around with procedures to do insert/update/delete on the relevant underlying table. Probably wouldn't be very easy to create or maintain, or very robust. There's a reason Oracle charge extra for this.
回答2:
Handmade Partitioning
- a working example for Oracle XE/SE
- Choose a partitioning key, for example: DOC_DATE - partition for every year.
Create 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
回答3:
Table partitioning is a feature of Oracle Enterprise Edition. To my knowledge, there is no such functionality in Standard Edition.
Would be happy to be proved wrong, mind you...
来源:https://stackoverflow.com/questions/5801407/what-feature-to-use-in-oracle-standard-edition-like-that-of-partitioning-in-orac