Partition Tables介紹及分區錶轉換

--====================數據庫

-- Partition Tablessession

--====================less

分區表相關概念:性能

當表數據不斷增長時,查詢數據庫速度就回變慢,應用程序性能就會降低,這個時候就該考慮對錶進行分區管理。分區表在邏輯上任然是一張完整的表,只是在物理上可能存放在多個表空間或物理文件上。當查詢數據是,不至於每次都掃描整張表,避免熱塊爭用。這樣比全表掃描能提供更好的數據處理能力和訪問能力。大數據

 

限制條件:ui

1. 簇表不適用與分區spa

2. 不能分割含有LONG,LOG RAW字段的表日誌

3. 索引朱指標(IOT)表不能進行範圍分區。orm

 

分區表優勢:索引

1. 加強可用性:

2. 減小關閉時間

3.可維護性

4.均衡I/O

5.提升性能

6.對應用,用戶透明

 

分區表類別:

1. 範圍分區 range partition

2. 哈希分區 hash partition

3. 列表分區 list partition

4. 引用分區 reference partition

5. 複合分區 composite partition

6. 間隔分區 interval partition

7. 系統分區

 

相關視圖:

select partitioning_type,table_name,interval from user_part_tables

select table_name,partition_name,tablespace_name,interval from user_tab_partitions;

select partitioned,owner,table_name from dba_tables;

顯示子分區信息,dba_tab_subpartitions

顯示分區列 dba_part_key_columns

顯示子分區列 dba_subpart_key_columns

 

分區轉換方法:

1. 導入導出 (imp/impdp)

2. 子查詢(subquery )

3. 分區轉發 partition exchange

4. 在線重定義 dbms_redefinition

 

1.1 Export/import method

採用邏輯導出導入很簡單,首先在源庫創建分區表,而後將數據導出,而後導入到新建的分區表便可,

1)  導出表:

expdp \'/ as sysdba\' directory=DATA_PUMP_DIR dumpfile=lhr_t.dmp  INCLUDE=TABLE:\"IN \(\'T\'\)\" SCHEMAS=LHR LOGFILE=expdp_T.log

2)  刪除表:drop table numbers;

3)  重建分區表的定義:

    create table numbers (qty number(3), name varchar2(15))

    partition by range (qty)

    (partition p1 values less than (501),

     partition p2 values less than (maxvalue));

4)  利用ignore=y來導入分區表:

impdp \'/ as sysdba\' directory=DATA_PUMP_DIR dumpfile=lhr_t.dmp SCHEMAS=LHR table_exists_action=APPEND LOGFILE=impdp_T.log

5) 查詢導入後的狀況

SYS@dlhr> SELECT D.TABLE_OWNER,D.TABLE_NAME,D.PARTITION_NAME FROM DBA_TAB_PARTITIONS d WHERE d.table_name='T';

 

2.1 利用原表重建分區表(插入)

這種方法的特色是:

優勢:方法簡單易用,因爲採用DDL語句,不會產生UNDO,且只產生少許REDO,效率相對較高,並且建表完成後數據已經在分佈到各個分區中了。

不足:對於數據的一致性方面還須要額外的考慮。因爲幾乎沒有辦法經過手工鎖定T表的方式保證一致性,在執行CREATE TABLE語句和RENAME T_NEW TO T語句直接的修改可能會丟失,若是要保證一致性,須要在執行完語句後對數據進行檢查,而這個代價是比較大的。另外在執行兩個RENAME語句之間執行的對T的訪問會失敗。

 適用於修改不頻繁的表,在閒時進行操做,表的數據量不宜太大。

 

主要有2種方式,ctas和insert方式,下邊分別介紹:

2.1.1  例一:CTAS+RENAME

利用CTAS語法在建立分區表的時候能夠一塊兒插入數據,也能夠建立好表結構再insert 進去。 CTAS這種方法採用DDL語句,不產生UNDO,只產生少許REDO,建表完成後數據已經在分佈到各個分區中。

模擬環境:

SQL> create table part1 (id number, time date);

表已建立。

 

SQL> insert into part1 select rownum,created from dba_objects;

已建立72807行。

 

SQL> commit;

提交完成。

 

SQL> select to_char(time,'yyyymmdd'),count(1) from part1 group by to_char(time,'yyyymmdd');

 

TO_CHAR(TIME,'YY COUNT(1)

---------------- ----------

20180323 39

20180324 39

20180326 39

20180321 4414

20180330 42

20180322 20

20180331 72

20180325 39

20180327 39

20100330 68018

20180329 46

 

已選擇11行。

 

SQL> create table t_new (id,time) partition by range(time)(

2 partition t1 values less than(to_date('20180323','yyyymmdd')),

3 partition t2 values less than(to_date('20180324','yyyymmdd')),

4 partition t3 values less than(to_date('20180325','yyyymmdd')),

5 partition t4 values less than(to_date('20180326','yyyymmdd')),

6 partition t5 values less than(to_date('20180329','yyyymmdd')),

7 partition t6 values less than (maxvalue)) as select id,time from part1;

 

表已建立。

注意:若是表數據量分廠,如上方法是很是損耗性能的,固然咱們可使用添加‘並行DDL’,‘加nologging’和‘查詢並行’方式來提升轉換性能。

 

SQL> create table t_new (id,time) partition by range(time)(

2 partition t1 values less than(to_date('20180323','yyyymmdd')),

3 partition t2 values less than(to_date('20180324','yyyymmdd')),

4 partition t3 values less than(to_date('20180325','yyyymmdd')),

5 partition t4 values less than(to_date('20180326','yyyymmdd')),

6 partition t5 values less than(to_date('20180329','yyyymmdd')),

7 partition t6 values less than (maxvalue))

as select /*+parallel*/ id,time from part1;

 

2.1.2  例二: Insert with a subquery method

這種方法就是先創建表結構而後使用insert 來實現。

建立分區表:

LHR@dlhr> CREATE TABLE T_LHR_20160527_NEW (ID NUMBER, TIME DATE)

  2  PARTITION BY RANGE (TIME)

  3      (PARTITION T1 VALUES LESS THAN (TO_DATE('201311', 'YYYYMM')),

  4       PARTITION T2 VALUES LESS THAN (TO_DATE('201606', 'YYYYMM')),

  5       PARTITION T3 VALUES LESS THAN (MAXVALUE));

 

從源表查詢插入到新表中:

LHR@dlhr> alter table T_LHR_20160527_NEW nologging;

 

Table altered.

 

LHR@dlhr> alter session enable parallel dml;

 

Session altered.

 

LHR@dlhr> insert /*+APPEND PARALLEL*/ into T_LHR_20160527_NEW (ID, TIME) select /*+PARALLEL(t3,4)*/  * from T_LHR_20160527;

注意:採用並行DML必須執行alter session enable parallel dml;

 

3.1  使用交換分區的方法(Partition exchange method)

這種方法的特色

 優勢:只是對數據字典中分區和表的定義進行了修改,沒有數據的修改或複製,效率最高。若是對數據在分區中的分佈沒有進一步要求的話,實現比較簡單。在執行完RENAME操做後,能夠檢查T_OLD中是否存在數據,若是存在的話,直接將這些數據插入到T中,能夠保證對T插入的操做不會丟失。

不足:仍然存在一致性問題,交換分區以後RENAME T_NEW TO T以前,查詢、更新和刪除會出現錯誤或訪問不到數據。若是要求數據分佈到多個分區中,則須要進行分區的SPLIT操做,會增長操做的複雜度,效率也會下降。

轉換以後,原表上的索引,約束須要從新創建。

 適用於包含大數據量的錶轉到分區表中的一個分區的操做。應儘可能在閒時進行操做。

3.1.1 模擬環境:

SQL> create table obj as select object_name,object_id,created from user_objects;

SQL> alter table obj add constraint obj_idx primary key(object_id);

已建立72807行。

建立分區:

create table obj_range(

object_name varchar2(128) ,

object_id number ,

created date,

constraint obj_indx primary key(object_id))

partition by range(created)(

partition r1 values less than(to_date('2018/06/01','yyyy/mm/dd')) tablespace p1,

partition r2 values less than(to_date('2018/07/01','yyyy/mm/dd')) tablespace p2,

partition r3 values less than(maxvalue));

 

表已建立。

 

注意:若是是單分區,須要r1分區包含轉換的表obj的全部數據,否則會報錯誤:

第 1 行出現錯誤:

ORA-14099: 未對指定分區限定表中的全部行

 

轉換數據:

SQL> alter table obj_range exchange partition r1 with table obj;

 

Table altered.

 

SQL> alter index SH.OBJ_INDX rebuild online;

 

Index altered.

 

SQL> insert into obj_range values('obj',100,to_date('2018/05/21','yyyy/mm/dd'));

 

1 row created.

 

查看分區信息:

SQL> select table_name,PARTITION_NAME,SUBPARTITION_COUNT,TABLESPACE_NAME from user_tab_partitions where table_name='OBJ_RANGE';

 

在數據轉換的時候很難保證有新數據插入,因此在轉換完成以後須要對老表數據查詢看是否有新數據存在,有的話直接摻入到新分區表中。

若是要求數據分佈到多個分區中,則須要進行分區的SPLIT操做。

原表跟分區表字段類型,長度,約束要保持一致。

轉換的分區表名字改爲跟老表同樣。

 

3.1.2. 若是分區表存在多個分區,就須要對分區進行單獨轉換

交換分區的操做步驟以下:

     1. 建立分區表,假設有2個分區,P1,P2.

     2. 建立表A存放P1規則的數據。

     3. 建立表B 存放P2規則的數據。

     4. 用表A 和P1 分區交換。 把表A的數據放到到P1分區

     5. 用表B 和p2 分區交換。 把表B的數據存放到P2分區。

SQL> alter table part exchange partition SAL1 with table sh.sales1;

 

Table altered.

 

SQL> alter table part exchange partition SAL2 with table sh.sales2;

 

Table altered.

 

 

 

4.1 利用在線重定義功能(DBMS_REDEFINITION)

這種分區的特色

優勢:保證數據的一致性,在大部分時間內,表T均可以正常進行DML操做。只在切換的瞬間鎖表,具備很高的可用性。這種方法具備很強的靈活性,對各類不一樣的須要都能知足。並且,能夠在切換前進行相應的受權並創建各類約束,能夠作到切換完成後再也不須要任何額外的管理操做。

 不足:實現上比上面兩種略顯複雜。

 適用於各類狀況。

在線重定義的大體操做流程以下:

       (1)建立基礎表A(數據表),若是存在,就不須要操做。

       (2)建立臨時的分區表B結構。

       (3)開始重定義,將基表A的數據導入臨時分區表B。

       (4)結束重定義,完成後在DB的 Name Directory裏,已經將2個表進行了交換。即此時基表A成了分區表,咱們建立的臨時分區表B 成了普通表。 此時咱們能夠刪除咱們建立的臨時表B。它已是普通表。

4.1.2 在線重定義功能

這個功能只在9.2.0.4之後的版本纔有,在線重定義表具備如下功能:

       (1)修改表的存儲參數;

       (2)將錶轉移到其餘表空間;

       (3)增長並行查詢選項;

       (4)增長或刪除分區;

       (5)重建表以減小碎片;

       (6)將堆表改成索引組織表或相反的操做;

       (7)增長或刪除一個列。

4.1.3在線重定義表的步驟

在線重定義的原理:物化視圖

在線重定義表的步驟:

1.選擇一種重定義方法:

存在兩種重定義方法,一種是基於主鍵、另外一種是基於ROWID。ROWID的方式不能用於索引組織表(IOT),並且重定義後會存在隱藏列M_ROW$$。默認採用主鍵的方式。

2.調用DBMS_REDEFINITION.CAN_REDEF_TABLE()過程,若是表不知足重定義的條件,將會報錯並給出緣由。

3.在用一個方案中創建一個空的中間表,根據重定義後你指望獲得的結構創建中間表。好比:採用分區表,增長了COLUMN等。

4.調用DBMS_REDEFINITION.START_REDEF_TABLE()過程,並提供下列參數:被重定義的表的名稱、中間表的名稱、列的映射規則、重定義方法。

若是映射方法沒有提供,則認爲全部包括在中間表中的列用於表的重定義。若是給出了映射方法,則只考慮映射方法中給出的列。若是沒有給出重定義方法,則認爲使用主鍵方式。

5.在中間表上創建觸發器、索引和約束,並進行相應的受權。任何包含中間表的完整性約束應將狀態置爲disabled。

當重定義完成時,中間表上創建的觸發器、索引、約束和受權將替換重定義表上的觸發器、索引、約束和受權。中間表上disabled的約束將在重定義表上enable。

6.(可選)若是在執行DBMS_REDEFINITION.START_REDEF_TABLE()過程和執行DBMS_REDEFINITION.FINISH_REDEF_TABLE()過程直接在重定義表上執行了大量的DML操做,那麼能夠選擇執行一次或屢次的SYNC_INTERIM_TABLE()過程,以減小最後一步執行FINISH_REDEF_TABLE()過程時的鎖定時間。

7.執行DBMS_REDEFINITION.FINISH_REDEF_TABLE()過程完成表的重定義。這個過程當中,原始表會被獨佔模式鎖定一小段時間,具體時間和表的數據量有關。

執行完FINISH_REDEF_TABLE()過程後,原始表重定義後具備了中間表的屬性、索引、約束、受權和觸發器。中間表上disabled的約束在原始表上處於enabled狀態。

8.(可選)能夠重命名索引、觸發器和約束。對於採用了ROWID方式重定義的表,包括了一個隱含列M_ROW$$。推薦使用下列語句經隱含列置爲UNUSED狀態或刪除。

ALTER TABLE TABLE_NAME SET UNUSED (M_ROW$$);

ALTER TABLE TABLE_NAME DROP UNUSED COLUMNS;

 

4.1.4 使用在線重定義的限制條件

使用在線重定義的一些限制條件:

(1) There must be enough space to hold two copies of the table.

(2) Primary key columns cannot be modified.

(3) Tables must have primary keys.

(4) Redefinition must be done within the same schema.

(5) New columns added cannot be made NOT NULL until after the redefinition operation.

(6) Tables cannot contain LONGs, BFILEs or User Defined Types.

(7) Clustered tables cannot be redefined.

(8) Tables in the SYS or SYSTEM schema cannot be redefined.

(9) Tables with materialized view logs or materialized views defined on them cannot be redefined.

(10) Horizontal sub setting of data cannot be performed during the redefinition.

?若是使用基於主鍵的方式,則原表後重定義後的表必須有相同的主鍵

?  若是使用基於ROWID的方式,則不能是索引組織表

?  若是原表上有物化視圖或者物化視圖日誌,則不能在線重定義

?  物化視圖容器表或者高級隊列表不能在線重定義

?  索引組織表的溢出表不能在線重定義

?  擁有BFILE,LOGN列的表不能在線重定義

?  Cluster中的表不能在線重定義

?  sys和system下的表不能在線重定義

?  臨時表不能在線重定義

?  不支持水平數據子集

?  在列映射時只能使用有肯定結果的表達式,如子查詢就不行

?  若是中間表有新增列,則不能有NOT NULL約束

?  原表和中間表之間不能有引用完整性

?  在線重定義沒法採用nologging

 

4.1.5 模擬環境:

 

SQL> create table obj(id number, time date);

表已建立。

SQL> insert into obj select rownum,created from dba_objects;

 

已建立72820行。

 

SQL> commit;

 

提交完成。

 

SQL> create index date_idx on obj(time);

 

索引已建立。

SQL> exec dbms_stats.gather_table_stats('PLAT','OBJ',cascade=>true);

 

PL/SQL 過程已成功完成。

 

建立臨時分區表:

create table obj_range(

object_name varchar2(128) ,

object_id number ,

created date,

constraint obj_indx primary key(object_id))

partition by range(created)(

partition r1 values less than(to_date('2018/06/01','yyyy/mm/dd')) tablespace p1,

partition r2 values less than(to_date('2018/07/01','yyyy/mm/dd')) tablespace p2,

partition r3 values less than(maxvalue));

 

表已建立。

 

表合法性檢查:檢查是否能夠執行在線重定義,若返回錯誤的話說明不能執行,須要根據提示修改表

SQL> exec dbms_redefinition.can_redef_table('PLAT','OBJ',dbms_redefinition.cons_use_pk);

BEGIN dbms_redefinition.can_redef_table('PLAT','OBJ',dbms_redefinition.cons_us

e_pk); END;

 

*

第 1 行出現錯誤:

ORA-12089: 不能聯機從新定義無主鍵的表 "PLAT"."OBJ"

ORA-06512: 在 "SYS.DBMS_REDEFINITION", line 139

ORA-06512: 在 "SYS.DBMS_REDEFINITION", line 1782

ORA-06512: 在 line 1

 

SQL> alter table plat.OBJ add constraint idx_pk primary key (id);

 

表已更改。

 

SQL> exec dbms_redefinition.can_redef_table('PLAT','OBJ',dbms_redefinition.cons_use_pk);

 

PL/SQL 過程已成功完成。

 

開始在線重定義:

SQL> exec dbms_redefinition.start_redef_table('PLAT','OBJ','OBJ_RANGE',dbms_redef

inition.cons_use_pk);

BEGIN dbms_redefinition.start_redef_table('PLAT','OBJ','OBJ_RANGE',dbms_redefinit

ion.cons_use_pk); END;

 

*

第 1 行出現錯誤:

ORA-42016: 中間表的形式與指定的列映射不匹配

ORA-06512: 在 "SYS.DBMS_REDEFINITION", line 52

ORA-06512: 在 "SYS.DBMS_REDEFINITION", line 1646

ORA-06512: 在 line 1

 

表列映射:

SQL> exec dbms_redefinition.start_redef_table('PLAT','OBJ','OBJ_RANGE','id id,time created_date ',dbms_redefinition.cons_use_pk);

PL/SQL 過程已成功完成。

 

SQL> select count(1) from OBJ;

 

COUNT(1)

----------

72821

 

SQL> select count(1) from OBJ_RANGE;

 

COUNT(1)

----------

72820

 

 

由上可見基表多一條數據,頗有多是在進行表在線重定義的時候,基表有數據插入,這個時候咱們須要讓基表數據跟中間表同步

SQL> exec dbms_redefinition.sync_interim_table('PLAT','OBJ','OBJ_RANGE');

 

PL/SQL 過程已成功完成。

相關文章
相關標籤/搜索