1. 程式人生 > >Partition Tables介紹及分割槽錶轉換

Partition Tables介紹及分割槽錶轉換

--====================

-- Partition Tables

--====================

分割槽表相關概念:

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

 

限制條件:

1. 簇表不適用與分割槽

2. 不能分割含有LONG,LOG RAW欄位的表

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

 

分割槽表優點:

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) 查詢匯入後的情況

[email protected]> 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 來實現。

建立分割槽表:

[email protected]> 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));

 

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

[email protected]> alter table T_LHR_20160527_NEW nologging;

 

Table altered.

 

[email protected]> alter session enable parallel dml;

 

Session altered.

 

[email protected]> 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 過程已成功完成。