一、Oracle分區簡介
ORACLE的分區是一種處理超大型表、索引等的技術。分區是一種“分而治之”的技術,通過将大表和索引分成可以管理的小塊,進而避免了對每個表作為一個大的、單獨的對象進行管理,為大量資料提供了可伸縮的性能。分區通過将操作配置設定給更小的存儲單元,減少了需要進行管理操作的時間,并通過增強的并行處理提高了性能,通過屏蔽故障資料的分區,還增加了可用性。
二、Oracle分區優缺點
優點:
增強可用性:如果表的某個分區出現故障,表在其他分區的資料仍然可用;
維護友善:如果表的某個分區出現故障,需要修複資料,隻修複該分區即可;
均衡I/O:可以把不同的分區映射到磁盤以平衡I/O,改善整個系統性能;
改善查詢性能:對分區對象的查詢可以僅搜尋自己關心的分區,提高檢索速度。
缺點:
分區表相關:已經存在的表沒有方法可以直接轉化為分區表。不過 Oracle 提供了線上重定義表的功能。
三、Oracle分區方法
範圍分區:
範圍分區就是對資料表中的某個值的範圍進行分區,根據某個值的範圍,決定将該資料存儲在哪個分區上。如根據序号分區,根據業務記錄的建立日期進行分區等。
Hash分區(散列分區):
散列分區為通過指定分區編号來均勻分布資料的一種分區類型,因為通過在I/O裝置上進行散列分區,使得這些分區大小一緻。
List分區(清單分區):
當你需要明确地控制如何将行映射到分區時,就使用清單分區方法。與範圍分區和散列分區所不同,清單分區不支援多列分區。如果要将表按列分區,那麼分區鍵就隻能由表的一個單獨的列組成,然而可以用範圍分區或散列分區方法進行分區的所有的列,都可以用清單分區方法進行分區。
範圍-散列分區(複合分區):
有時候我們需要根據範圍分區後,每個分區内的資料再散列地分布在幾個表空間中,這樣我們就要使用複合分區。複合分區是先使用範圍分區,然後在每個分區内再使用散列分區的一種分區方法(注意:先一定要進行範圍分區)
範圍-清單分區(複合分區):
範圍和清單技術的組合,首先對表進行範圍分區,然後用清單技術對每個範圍分區再次分區。與組合範圍-散列分區不同的是,每個子分區的所有内容表示資料的邏輯子集,由适當的範圍和清單分區設定來描述。(注意:先一定要進行範圍分區)
四、Oracle表分區表操作
--Partitioning 是否為true
select * from v$option s order by s.PARAMETER desc
--建立表空間
CREATE TABLESPACE "PARTION_03"
LOGGING
DATAFILE 'D:ORACLEORADATAJZHUAPARTION_03.dbf' SIZE 50M
EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO
--删除表空間
drop tablespace partion_01
--範圍 分區技術
create table Partition_Test
(
PID number not null,
PITEM varchar2(200),
PDATA date not null
)
partition by range(PID)
(
partition part_01 values less than(50000) tablespace dinya_space01,
partition part_02 values less than(100000) tablespace dinya_space02,
partition part_03 values less than(maxvalue) tablespace dinya_space03
)
create table Partition_TTest
(
PID number not null,
PITEM varchar2(200),
PDATA date not null
)
partition by range(PDATA)
(
partition part_t01 values less than(to_date('2004-01-01','yyyy-mm-dd')) tablespace dinya_space01,
partition part_t02 values less than(to_date('2008-01-01','yyyy-mm-dd')) tablespace dinya_space02,
partition part_t03 values less than(maxvalue) tablespace dinya_space03
)
insert into Partition_Test(PID,PITEM,PDATA) select h.id,h.userid,h.rectime from st_handle h
select * from Partition_Test partition(part_01) t where t.pid = '1961'
--hash 分區技術
create table Partition_HashTest
(
PID number not null,
PITEM varchar2(200),
PDATA date not null
)
partition by hash(PID)
(
partition part_h01 tablespace dinya_space01,
partition part_h02 tablespace dinya_space02,
partition part_h03 tablespace dinya_space03
)
insert into Partition_HashTest(PID,PITEM,PDATA) select h.id,h.userid,h.rectime from st_handle h
select * from Partition_HashTest partition(part_h03) t where t.pid = '1961'
--複合分區技術
create table Partition_FHTest
(
PID number not null,
PITEM varchar2(200),
PDATA date not null
)
partition by range(PDATA) subpartition by hash(PID) subpartitions 3 store in (dinya_space01,dinya_space02,dinya_space03)
(
partition part_fh01 values less than(to_date('2004-01-01','yyyy-mm-dd')) tablespace dinya_space01,
partition part_fh02 values less than(to_date('2008-01-01','yyyy-mm-dd')) tablespace dinya_space02,
partition part_fh03 values less than(maxvalue) tablespace dinya_space03
)
insert into Partition_FHTest(PID,PITEM,PDATA) select h.id,h.userid,h.rectime from st_handle h
select * from Partition_FHTest partition(part_fh02) t where t.pid = '1961'
select * from Partition_FHTest partition(part_fh03) t
--速度比較
select * from st_handle h where h.rectime > to_date('2008-01-01','yyyy-mm-dd');
select * from Partition_FHTest partition(part_fh03) t where t.pdata > to_date('2008-01-01','yyyy-mm-dd');
--分區表操作
--增加一個分區
alter table Partition_Test add partition part_05 values less than (10020) tablespace dinya_space03
--查詢分區資料
select * from Partition_FHTest partition(part_fh02) t
--修改分區裡的資料
update Partition_FHTest partition(part_fh02) t set t.PITEM = 'JZHUA' where t.pid = '1961'
--删除分區裡的資料
delete from Partition_FHTest partition(part_fh02) t where t.pid = '1961'
--合并分區
create table Partition_HB
(
PID number not null,
PITEM varchar2(200),
PDATA date not null
)
partition by range(PID)
(
partition part_01 values less than(50000) tablespace dinya_space01,
partition part_02 values less than(100000) tablespace dinya_space02,
partition part_03 values less than(maxvalue) tablespace dinya_space03
)
insert into Partition_HB(PID,PITEM,PDATA) select h.id,h.userid,h.rectime from st_handle h
select * from Partition_HB partition(part_03) t where t.pid = '100001'
alter table Partition_HB merge partitions part_01,part_02 into partition part_02;
--拆分分區
-- spilt partition 分區名 at(這裡是一個臨界區,比如:50000就是說小于50000的放在part_01,而大于50000的放在part_02中)
alter table Partition_HB split Partition part_02 at (50000) into (Partition part_01 tablespace dinya_space01, Partition part_02 tablespace dinya_space02);
--更改分區名
alter table Partition_HB rename Partition part_01_test to part_02;
五、Oracle索引分區表操作
分區表和一般表一樣可以建立索引,分區表可以建立局部索引和全局索引。當分區中出現許多事務并且要保證所有分區中的資料記錄的唯一性時采用全局索引。全局索引建立時 global 子句允許指定索引的範圍值,這個範圍值為索引字段的範圍值。其實理論上有3中分區索引。
?Global索引(全局索引):
對于 global 索引,可以選擇是否分區,而且索引的分區可以不與表分區相對應。當對分區進行維護操作時,通常會導緻全局索引的 Invalid,必須在執行完操作後 Rebuild。Oracle9i 提供了 Update Global Indexes 語句,可以在進行分區維護的同時重建全局索引。
1:索引資訊的存放位置與父表的Partition(分區)資訊完全不相幹。甚至父表是不是分區表都無所謂的。
create index dinya_idx_t on dinya_test(item_id) global partition by range(item_id) (
partition idx_1 values less than (1000) tablespace dinya_space01,
partition idx_2 values less than (10000) tablespace dinya_space02,
partition idx_3 values less than (maxvalue) tablespace dinya_space03
);
2:但是在這種情況下,如果父表是分區表,要删除父表的一個分區都必須要更新Global Index ,否則索引資訊不正确
ALTER TABLE TableName DROP PARTITION PartitionName Update Global Indexes
Local索引(局部索引):
對于 local 索引,每一個表分區對應一個索引分區(就是說一個分區表一個字段隻可以建一個局部索引),當表的分區發生變化時,索引的維護由 Oracle 自動進行;
1:索引資訊的存放位置依賴于父表的Partition(分區)資訊,換句話說建立這樣的索引必須保證父表是Partition(分區),索引資訊存放在父表的分區所在的表空間。
2:但是僅可以建立在父表為HashTable或者composite分區表的。
3:僅可以建立在父表為HashTable或者composite分區表的。并且指定的分區數目要與父表的分區數目要一緻。
create index dinya_idx_t on dinya_test(item_id) local (
partition idx_1 tablespace dinya_space01,
partition idx_2 tablespace dinya_space02,
partition idx_3 tablespace dinya_space03
);
不指定索引分區名直接對整個表建立索引
create index dinya_idx_t on dinya_test(item_id);
-------------------------------------------------------分區2-----------------------------------------------------------------------------
最近在做一個客戶關系管理系統,項目做的到不是非常成功,可還是學到了不少的知識,由于資料量很大,沒有專門的oracle資料庫人員支援,對資料庫優化管理等也隻有我這個約懂一點的人上了。在對資料庫優化上有一點點心得寫出來希望能同大家一起學習和交流。
資料庫大表的優化:采用蔟表(clustered tables)及蔟索引(Clustered Index)
蔟表和蔟索引是oracle所提供的一種技術,其基本思想是将幾張具有相同資料項、并且經常性一起使用的表通過共享資料塊(data block)的模式存放在一起。各表間的共同字段作為蔟鍵值(cluster key),資料庫在通路資料時,首先找到蔟鍵值,以此同時獲得若幹張表的相關資料。蔟表所能帶來的好處是可以減少I/O和減少存儲空間,其中我更看重前者。采用表分區(partition)
表分區技術是在超大型資料庫(VLDB)中将大表及其索引通過分區(patition)的形式分割為若幹較小、可管理的小塊,并且每一分區可進一步劃分為更小的子分區(sub partition)。而這種分區對于應用來說是透明的。通過對表進行分區,可以獲得以下的好處:
1)減少資料損壞的可能性。
2)各分區可以獨立備份和恢複,增強了資料庫的可管理性。
3)可以控制分區在硬碟上的分布,以均衡IO,改善了資料庫的性能。
蔟表與表分區技術的側重點各有不同,前者側重于改進關聯表間查詢的效率,而表分區側重于大表的可管理性及局部查詢的性能。而這兩項對于我的系統來說都是極為重要。由于本人技術限制,目前尚不确定兩者是否可以同時實作,有那位在這方面有經驗的給點指導将不勝感激。
在兩者無法同時實作的情況下,應依照需實作的功能有所取舍。綜合兩種模式的優缺點,我認為采用表分區技術較為适用于我們的應用。
Oracle的表分區有以下幾種類型:
1)範圍分區:将表按某一字段或若幹個字段的取值範圍分區。
2)hash分區:将表按某一字段的值均勻地分布到若幹個指定的分區。
3)複合分區:結合了前面兩種分區類型的優點,首先通過值範圍将表進行分區,然後以hash模式将資料進一步均勻配置設定至實體存儲位置。
綜合考慮各項因素,以第三種類型最為優越。(本人實在技術有限僅采用了第1種範圍分區,因為比較簡單,便于管理)
優化的具體步驟:
1.确定需要優化分區的表:
經過對系統資料庫表結構和字段,應用程式的分析,現在确定那些大表需要進行分區:
如帳戶交易明細表acct_detail.
2.确定表分區的方法和分區鍵:
分區類型:采用範圍分區。
分 區 鍵:
按trans_date(交易時間)字段進行範圍分區.
3.确定分區鍵的分區範圍,及打算分多少分區:
如:帳戶交易明細表acct_detail.
根據字段(trans_date)分成一下分區:
1).分區1:09/01/2003
2).分區2:10/01/2003
3).分區3:11/01/2003
4).分區4:12/01/2003
5).分區5:01/01/2004
6).分區6:02/01/2004
該表明顯需要在以後增加分區。
4.建立分區表空間和分區索引空間
1).建立表的各個分區的表空間:
1.分區1:crm_detail_200309
CREATE TABLESPACE crm_detail_200309 DATAFILE
‘/u1/oradata/orcl/crm_detail_20030901.dbf’
SIZE 2000M EXTENT MANAGEMENT LOCAL UNIFORM size 16M;
其它月份以後同以上(我在此采用oracle的表空間本地管理的方法)。
2). 建立分區索引表空間
1.分區1:index_detail_200309
CREATE TABLESPACE index_detail_200309 DATAFILE
‘/u3/oradata/orcl/index_detail_20030901.dbf’
SIZE 2000M EXTENT MANAGEMENT LOCAL UNIFORM size 16M;
5.建立基于分區的表:
create table table name
(
........
enable row movement --此語句是能修改行分區鍵值,也就是如不添加該 句不能修改記錄的分區鍵值,不能使記錄分區遷移
PARTITION BY RANGE (TRANS_DATE)
(
PARTITION crm_detail_200309 VALUES LESS THAN
(TO_DATE (‘09/01/2003’,’mm/dd/yyyy’
TABLESPACE crm_detail_200309,
其他分區.....
;
6.建立基于分區的索引:
create index index_name on table_name (分區鍵+…)
global --這裡是全局分區索引,也可以建本地索引
PARTITION BY RANGE (TRANS_DATE)
(
PARTITION index_detail_200309 VALUES LESS THAN
(TO_DATE ('09/01/2003','mm/dd/yyyy' )
TABLESPACE index_detail_200309,
其他索引分區...
;
對表的分區就這樣完成了,第一次主要确定表分區的分區策約是最重要的,可我覺得對表分區難在以後對表分區的管理上面,因為随着資料量的增加,表分區必然存在删除,擴容,增加等。在這些過程中還牽涉到全局等索引,因為對分區表進行ddl操作為破壞全局索引,故全局索引必須在ddl後要重 rebuild.
---------------------------------------------------------------------分區3-----------------------------------------------------------------
Oracle的普通表沒有辦法通過修改屬性的方式直接轉化為分區表,必須通過重建的方式進行轉變,下面介紹三種效率比較高的方法,并說明它們各自的特點。
方法一:利用原表重建分區表。
步驟:
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, TIME DATE);
表已建立。
SQL> INSERT INTO T SELECT ROWNUM, CREATED FROM DBA_OBJECTS;
已建立6264行。
SQL> COMMIT;
送出完成。
SQL> CREATE TABLE T_NEW (ID, TIME) PARTITION BY RANGE (TIME)
2 (PARTITION P1 VALUES LESS THAN (TO_DATE(''2004-7-1'', ''YYYY-MM-DD'')),
3 PARTITION P2 VALUES LESS THAN (TO_DATE(''2005-1-1'', ''YYYY-MM-DD'')),
4 PARTITION P3 VALUES LESS THAN (TO_DATE(''2005-7-1'', ''YYYY-MM-DD'')),
5 PARTITION P4 VALUES LESS THAN (MAXVALUE))
6 AS SELECT ID, TIME FROM T;
表已建立。
SQL> RENAME T TO T_OLD;
表已重命名。
SQL> RENAME T_NEW TO T;
表已重命名。
SQL> SELECT COUNT(*) FROM T;
COUNT(*)
----------
6264
SQL> SELECT COUNT(*) FROM T PARTITION (P1);
COUNT(*)
----------
SQL> SELECT COUNT(*) FROM T PARTITION (P2);
COUNT(*)
----------
6246
SQL> SELECT COUNT(*) FROM T PARTITION (P3);
COUNT(*)
----------
18
優點:方法簡單易用,由于采用DDL語句,不會産生UNDO,且隻産生少量REDO,效率相對較高,而且建表完成後資料已經在分布到各個分區中了。
不足:對于資料的一緻性方面還需要額外的考慮。由于幾乎沒有辦法通過手工鎖定T表的方式保證一緻性,在執行CREATE TABLE語句和RENAME T_NEW TO T語句直接的修改可能會丢失,如果要保證一緻性,需要在執行完語句後對資料進行檢查,而這個代價是比較大的。另外在執行兩個RENAME語句之間執行的對T的通路會失敗。
适用于修改不頻繁的表,在閑時進行操作,表的資料量不宜太大。
方法二:使用交換分區的方法。
步驟:
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, TIME DATE);
表已建立。
SQL> INSERT INTO T SELECT ROWNUM, CREATED FROM DBA_OBJECTS;
已建立6264行。
SQL> COMMIT;
送出完成。
SQL> CREATE TABLE T_NEW (ID NUMBER PRIMARY KEY, TIME DATE) PARTITION BY RANGE (TIME)
2 (PARTITION P1 VALUES LESS THAN (TO_DATE(''2005-7-1'', ''YYYY-MM-DD'')),
3 PARTITION P2 VALUES LESS THAN (MAXVALUE));
表已建立。
SQL> ALTER TABLE T_NEW EXCHANGE PARTITION P1 WITH TABLE T;
表已更改。
SQL> RENAME T TO T_OLD;
表已重命名。
SQL> RENAME T_NEW TO T;
表已重命名。
SQL> SELECT COUNT(*) FROM T;
COUNT(*)
----------
6264
優點:隻是對資料字典中分區和表的定義進行了修改,沒有資料的修改或複制,效率最高。如果對資料在分區中的分布沒有進一步要求的話,實作比較簡單。在執行完RENAME操作後,可以檢查T_OLD中是否存在資料,如果存在的話,直接将這些資料插入到T中,可以保證對T插入的操作不會丢失。
不足:仍然存在一緻性問題,交換分區之後RENAME T_NEW TO T之前,查詢、更新和删除會出現錯誤或通路不到資料。如果要求資料分布到多個分區中,則需要進行分區的SPLIT操作,會增加操作的複雜度,效率也會降低。
适用于包含大資料量的表轉到分區表中的一個分區的操作。應盡量在閑時進行操作。
方法三:Oracle9i以上版本,利用線上重定義功能
步驟:
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, TIME DATE);
表已建立。
SQL> INSERT INTO T SELECT ROWNUM, CREATED FROM DBA_OBJECTS;
已建立6264行。
SQL> COMMIT;
送出完成。
SQL> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(USER, ''T'', DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL 過程已成功完成。
SQL> CREATE TABLE T_NEW (ID NUMBER PRIMARY KEY, TIME DATE) PARTITION BY RANGE (TIME)
2 (PARTITION P1 VALUES LESS THAN (TO_DATE(''2004-7-1'', ''YYYY-MM-DD'')),
3 PARTITION P2 VALUES LESS THAN (TO_DATE(''2005-1-1'', ''YYYY-MM-DD'')),
4 PARTITION P3 VALUES LESS THAN (TO_DATE(''2005-7-1'', ''YYYY-MM-DD'')),
5 PARTITION P4 VALUES LESS THAN (MAXVALUE));
表已建立。
SQL> EXEC DBMS_REDEFINITION.START_REDEF_TABLE(USER, ''T'', ''T_NEW'', -
> ''ID ID, TIME TIME'', DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL 過程已成功完成。
SQL> EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE(''YANGTK'', ''T'', ''T_NEW'');
PL/SQL 過程已成功完成。
SQL> SELECT COUNT(*) FROM T;
COUNT(*)
----------
6264
SQL> SELECT COUNT(*) FROM T PARTITION (P2);
COUNT(*)
----------
6246
SQL> SELECT COUNT(*) FROM T PARTITION (P3);
COUNT(*)
----------
18
優點:保證資料的一緻性,在大部分時間内,表T都可以正常進行DML操作。隻在切換的瞬間鎖表,具有很高的可用性。這種方法具有很強的靈活性,對各種不同的需要都能滿足。而且,可以在切換前進行相應的授權并建立各種限制,可以做到切換完成後不再需要任何額外的管理操作。
不足:實作上比上面兩種略顯複雜。
适用于各種情況。
這裡隻給出了線上重定義表的一個最簡單的例子,詳細的描述和例子可以參考下面兩篇文章。
Oracle的線上重定義表功能:http://blog.itpub.net/post/468/12855
Oracle的線上重定義表功能(二):http://blog.itpub.net/post/468/12962
二、索引分區的概念 及建索引方法
索引分區是在您建立了表分區後,要建索引就必須是建立索引分區。分2大類:一類是把索引資訊建立在各個分區上,這叫局部索引分區(或叫本地索引分區)。另一類是把索引集中起來,叫全局索引。
1、局部索引又分2類。
建立方法:
create index ind_1 on dept (deptno)
local
(partition d1 ,
partition d2);
(1)局部字首索引分區和局部非字首分區。如果您拟建立的索引的首個字段,和進行分區時的range列一樣,那就是局部字首索引分區。
優點是:理論上(我認為的),比方說您以年代為range分區,2007年一個分區、2008年一個分區,然後您又在這個時間列上建立了局部字首索引分區,那麼ORACLE就會直接利用這個區上的索引僅進行這個分區上的搜尋,是以效率會很高。
在我建立的2000萬的表中進行查詢,實踐是,這個局部字首複合索引的花銷cost是5,而沒有分區前是4。當然這也無所謂了。又進行了其他幾個查詢,其cost都相差無幾。
(2)局部非字首索引。如果您建立索引的列的首個字段不是range列,那麼就叫局部非字首索引。
優點是:如果您查一個電話号碼,它在每年都會出現,當您要count彙總時,這種索引就會同時把這幾個分區進行并行處理查詢,速度理論上要快。
但我的試驗比較令我失望:我建了一個2000萬的無分區的表,然後把這個表又複制了一遍,進行了6個分區。但結果在對某列進行查詢統計時,如果在一個分區,兩者速度相差不大,分區的查詢速度是:0.25m,無分區的查詢速度是:0.065m。但在我期望的跨區統計時,分區的第一次統計時間是:61.875m,第二次是:10m;而無分區的表僅為:3.703m。
2、全局索引。
建立方法:
create index ind_2 on sales (amount_sold)
global partition by range (amount_sold)
(partition d1 ,
partition d2);
因為全局索引的首個字段必須是range字段,是以就無所謂字首和非字首了,都是字首。
經過試驗,我覺得建立全局索引的速度要略遜于局部字首索引。
也可能是我的能力問題,現在覺得建立分區還不然不建立索引。如果大家能給我解惑
------------------------------------------------------------------------------------------------------------------------
Oracle的普通表沒有辦法通過修改屬性的方式直接轉化為分區表,必須通過重建的方式進行轉變,下面介紹三種效率比較高的方法,并說明它們各自的特點。
方法一:利用原表重建分區表。
步驟:
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, TIME DATE);
表已建立。
SQL> INSERT INTO T SELECT ROWNUM, CREATED FROM DBA_OBJECTS;
已建立6264行。
SQL> COMMIT;
送出完成。
SQL> CREATE TABLE T_NEW (ID, TIME) PARTITION BY RANGE (TIME)
2 (PARTITION P1 VALUES LESS THAN (TO_DATE('2004-7-1', 'YYYY-MM-DD')),
3 PARTITION P2 VALUES LESS THAN (TO_DATE('2005-1-1', 'YYYY-MM-DD')),
4 PARTITION P3 VALUES LESS THAN (TO_DATE('2005-7-1', 'YYYY-MM-DD')),
5 PARTITION P4 VALUES LESS THAN (MAXVALUE))
6 AS SELECT ID, TIME FROM T;
表已建立。
SQL> RENAME T TO T_OLD;
表已重命名。
SQL> RENAME T_NEW TO T;
表已重命名。
SQL> SELECT COUNT(*) FROM T;
COUNT(*)
----------
6264
SQL> SELECT COUNT(*) FROM T PARTITION (P1);
COUNT(*)
----------
SQL> SELECT COUNT(*) FROM T PARTITION (P2);
COUNT(*)
----------
6246
SQL> SELECT COUNT(*) FROM T PARTITION (P3);
COUNT(*)
----------
18
優點:方法簡單易用,由于采用DDL語句,不會産生UNDO,且隻産生少量REDO,效率相對較高,而且建表完成後資料已經在分布到各個分區中了。
不足:對于資料的一緻性方面還需要額外的考慮。由于幾乎沒有辦法通過手工鎖定T表的方式保證一緻性,在執行CREATE TABLE語句和RENAME T_NEW TO T語句直接的修改可能會丢失,如果要保證一緻性,需要在執行完語句後對資料進行檢查,而這個代價是比較大的。另外在執行兩個RENAME語句之間執行的對T的通路會失敗。
适用于修改不頻繁的表,在閑時進行操作,表的資料量不宜太大。
方法二:使用交換分區的方法。
步驟:
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, TIME DATE);
表已建立。
SQL> INSERT INTO T SELECT ROWNUM, CREATED FROM DBA_OBJECTS;
已建立6264行。
SQL> COMMIT;
送出完成。
SQL> CREATE TABLE T_NEW (ID NUMBER PRIMARY KEY, TIME DATE) PARTITION BY RANGE (TIME)
2 (PARTITION P1 VALUES LESS THAN (TO_DATE('2005-7-1', 'YYYY-MM-DD')),
3 PARTITION P2 VALUES LESS THAN (MAXVALUE));
表已建立。
SQL> ALTER TABLE T_NEW EXCHANGE PARTITION P1 WITH TABLE T;
表已更改。
SQL> RENAME T TO T_OLD;
表已重命名。
SQL> RENAME T_NEW TO T;
表已重命名。
SQL> SELECT COUNT(*) FROM T;
COUNT(*)
----------
6264
優點:隻是對資料字典中分區和表的定義進行了修改,沒有資料的修改或複制,效率最高。如果對資料在分區中的分布沒有進一步要求的話,實作比較簡單。在執行完RENAME操作後,可以檢查T_OLD中是否存在資料,如果存在的話,直接将這些資料插入到T中,可以保證對T插入的操作不會丢失。
不足:仍然存在一緻性問題,交換分區之後RENAME T_NEW TO T之前,查詢、更新和删除會出現錯誤或通路不到資料。如果要求資料分布到多個分區中,則需要進行分區的SPLIT操作,會增加操作的複雜度,效率也會降低。
适用于包含大資料量的表轉到分區表中的一個分區的操作。應盡量在閑時進行操作。
方法三:Oracle9i以上版本,利用線上重定義功能
步驟:
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, TIME DATE);
表已建立。
SQL> INSERT INTO T SELECT ROWNUM, CREATED FROM DBA_OBJECTS;
已建立6264行。
SQL> COMMIT;
送出完成。
SQL> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(USER, 'T', DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL 過程已成功完成。
SQL> CREATE TABLE T_NEW (ID NUMBER PRIMARY KEY, TIME DATE) PARTITION BY RANGE (TIME)
2 (PARTITION P1 VALUES LESS THAN (TO_DATE('2004-7-1', 'YYYY-MM-DD')),
3 PARTITION P2 VALUES LESS THAN (TO_DATE('2005-1-1', 'YYYY-MM-DD')),
4 PARTITION P3 VALUES LESS THAN (TO_DATE('2005-7-1', 'YYYY-MM-DD')),
5 PARTITION P4 VALUES LESS THAN (MAXVALUE));
表已建立。
SQL> EXEC DBMS_REDEFINITION.START_REDEF_TABLE(USER, 'T', 'T_NEW', -
> 'ID ID, TIME TIME', DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL 過程已成功完成。
SQL> EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE('YANGTK', 'T', 'T_NEW');
PL/SQL 過程已成功完成。
SQL> SELECT COUNT(*) FROM T;
COUNT(*)
----------
6264
SQL> SELECT COUNT(*) FROM T PARTITION (P2);
COUNT(*)
----------
6246
SQL> SELECT COUNT(*) FROM T PARTITION (P3);
COUNT(*)
----------
18
優點:保證資料的一緻性,在大部分時間内,表T都可以正常進行DML操作。隻在切換的瞬間鎖表,具有很高的可用性。這種方法具有很強的靈活性,對各種不同的需要都能滿足。而且,可以在切換前進行相應的授權并建立各種限制,可以做到切換完成後不再需要任何額外的管理操作。
不足:實作上比上面兩種略顯複雜。
适用于各種情況。
這裡隻給出了線上重定義表的一個最簡單的例子,詳細的描述和例子可以參考下面兩篇文章。
Oracle的線上重定義表功能:http://blog.itpub.net/post/468/12855
Oracle的線上重定義表功能(二):http://blog.itpub.net/post/468/12962
索引也可以進行分區,分區索引有兩種類型:global和local。對于local索引,每一個表分區對應一個索引分區,當表的分區發生變化時,索引的維護由Oracle自動進行。對于global索引,可以選擇是否分區,而且索引的分區可以不與表分區相對應。當對分區進行維護操作時,通常會導緻全局索引的INVALDED,必須在執行完操作後REBUILD。Oracle9i提供了UPDATE GLOBAL INDEXES語句,可以使在進行分區維護的同時重建全局索引。
全局索引可以包含多個分區的值 局部索引比全局索引容易管理,而全局索引比較快
注意:不能為散列分區 或者 子分區建立全局索引
Oracle的分區功能十分強大。不過用起來發現有兩點不大友善:
第一是已經存在的表沒有方法可以直接轉化為分區表。不過Oracle提供了線上重定義表的功能,可以通過這種方式來完成普通表到分區表的轉化。可以參考這個例子:http://blog.itpub.net/post/468/13091
第二點是如果采用了local分區索引,那麼在增加表分區的時候,索引分區的表空間是不可控制的。如果希望将表和索引的分區分開到不同的表空間且不同索引分區也分散到不同的表空間中,那麼隻能在增加分區後,對新增的分區索引單獨rebuild。
Oracle最大允許存在多少個分區呢?
我們可以從Oracle的Concepts手冊上找到這個資訊,對于Oracle9iR2:
Tables can be partitioned into up to 64,000 separate partitions.
對于Oracle10gR2,Oracle增強了分區特性:
Tables can be partitioned into up to 1024K-1 separate partitions.
關于何時應該進行分區,Oracle有如下建議:
■ Tables greater than 2GB should always be considered for partitioning.
■ Tables containing historical data, in which new data is added into the newest partition. A typical example is a historical table where only the current month's data is updatable and the other 11 months are read only.