Oracle 11g表分割槽與索引分割槽(《Oracle從入門到精通》讀書筆記4)
一、概述
分割槽表的用途和優點:
1. 降低故障引起的損失;
2. 均衡I/O,減少競爭;
3. 提高查詢速度,這一點在資料倉庫的TP查詢特別有用;
*TP查詢:Transaction Processing,事務處理查詢?這點不太清楚、網上資料也少,沒查到
二、建立表分割槽
*首先通過下列語句找到目標資料庫中的表空間名:
select tablespace_name,file_name,bytes/1024/1024 as MB from dba_data_files order by tablespace_name;
1. 範圍分割槽:關鍵字RANGE,建立這種分割槽後,插入的資料會根據指定的分割槽鍵值範圍進行分佈,當資料在範圍內均勻分佈時,效能最好。
指定某一列的鍵值建立分割槽表:
例:建立一個商品零售表、包含四個分割槽,記錄按照日期所在的季度分割槽:
create table ware_retail_part --建立一個描述商品零售的資料表 ( id integer primary key,--銷售編號 retail_date date,--銷售日期 ware_name varchar2(50)--商品名稱 ) partition by range(retail_date) ( --2011年第一個季度為part_01分割槽 partition par_01 values less than(to_date('2011-04-01','yyyy-mm-dd')) tablespace TB_3, --2011年第二個季度為part_02分割槽 partition par_02 values less than(to_date('2011-07-01','yyyy-mm-dd')) tablespace TB_4, --2011年第三個季度為part_03分割槽 partition par_03 values less than(to_date('2011-10-01','yyyy-mm-dd')) tablespace TB_3, --2011年第四個季度為part_04分割槽 partition par_04 values less than(to_date('2012-01-01','yyyy-mm-dd')) tablespace TB_4 );
之後我們向該表插入幾條記錄看下結果:
insert into ware_retail_part values(1,to_date('2011-01-21','yyyy-mm-dd'),'Pad');
insert into ware_retail_part values(2,to_date('2011-04-01','yyyy-mm-dd'),'Pad');insert into ware_retail_part values(3,to_date('2011-07-25','yyyy-mm-dd'),'Pad');
insert into ware_retail_part values(4,to_date('2011-12-31','yyyy-mm-dd'),'Pad');
查詢該表中某個分割槽中的資料:
select *from ware_retail_part partition(par_01);
指定某幾列的鍵值建立分割槽表:
例:建立一個商品零售表、包含四個分割槽,按照日期和銷售序號進行分割槽:
create table ware_retail_part2 --建立一個描述商品零售的資料表
(
id integer primary key,--銷售編號
retail_date date,--銷售日期
ware_name varchar2(50)--商品名稱
)
partition by range(id,retail_date)
(
--part_01分割槽
partition par_01 values less than(10,to_date('2011-04-01','yyyy-mm-dd')) tablespace TB_3,
--part_02分割槽
partition par_02 values less than(20,to_date('2011-07-01','yyyy-mm-dd')) tablespace TB_4,
--part_03分割槽
partition par_03 values less than(maxvalue,maxvalue) tablespace TB_3
);
最後一句有必要提一下,意思就是ID大於20、日期大於2011-07-01的記錄全部存到第三個分割槽。
*注:這裡指定的表空間塊大小要一致,否則會報ORA-14519錯誤;這時需要修改對應表空間的塊大小:
alter system set db_block_size=xxxx;
如果修改不了,可以參考這篇文章:http://blog.csdn.net/victory_xing126/article/details/45126247
2. 雜湊分割槽:又叫Hash分割槽;實在列的取值範圍難以確定的情況下采用的分割槽方法。一般,下面幾種情況可以採用Hash分割槽:
·DBA無法獲知具體的資料值;
·資料的分佈有Oracle處理;
·每個分割槽有自己的表空間。
例1:建立一個商品零售表,將表的ID列設為Hash鍵來決定記錄的所在分割槽
create table ware_retail_part3 --建立一個描述商品零售的資料表
(
id integer primary key,--銷售編號
retail_date date,--銷售日期
ware_name varchar2(50)--商品名稱
)
partition by hash(id)
(
partition par_01 tablespace TB_3,
partition par_02 tablespace TB_4
);
此時,向其中插入資料,Oracle會自動計算ID列的Hash值、從而決定該條記錄該被存到哪個分割槽。
insert into ware_retail_part3 values(181,to_date('2011-01-21','yyyy-mm-dd'),'Pad');
insert into ware_retail_part3 values(271,to_date('2011-04-01','yyyy-mm-dd'),'Pad');insert into ware_retail_part3 values(301,to_date('2011-07-25','yyyy-mm-dd'),'Pad');
insert into ware_retail_part3 values(431,to_date('2011-12-31','yyyy-mm-dd'),'Pad');
如果想知道某條記錄被插入到哪個分割槽中,可以用下面的語句查詢:select ora_hash(Hash鍵值, 分割槽數) from dual;
例2:建立一個分割槽表,讓系統自動生成分割槽名,並把這兩個分割槽分別放到表空間tb_3,tb_4中:
create table ware_retail_part4 --建立一個描述商品零售的資料表
(
id integer primary key,--銷售編號
retail_date date,--銷售日期
ware_name varchar2(50)--商品名稱
)
partition by hash(id)
<pre name="code" class="sql">partitions 2
store in(tb_3,tb_4);
例3:建立一個分割槽表,並指定其初始化空間大小為2MB:
create table ware_retail_part5 --建立一個描述商品零售的資料表
(
id integer primary key,--銷售編號
retail_date date,--銷售日期
ware_name varchar2(50)--商品名稱
)
storage(initial 2048k)
partition by hash(id)
(
partition par_01 tablespace TB_3,
partition par_02 tablespace TB_4
);
3. 列表分割槽:與範圍分割槽類似,但分割槽依據是根據分割槽鍵的“具體值”來決定
例1:儲存客戶資訊的clients表,以province列的值建立列表分割槽:
create table clients
(
id integer primary key,
name varchar2(50),
province varchar2(20)
)
partition by list(province)
(
partition shandong values('山東省') tablespace TB_3,
partition guangdong values('廣東省') tablespace TB_4,
partition yunnan values('雲南省') tablespace TB_3
);
向其中插入資料:
insert into clients values (19,'East','雲南省');
insert into clients values (29,'West','廣東省');
insert into clients values (09,'North','山東省');
查下結果:
select * from clients partition(yunnan);
select * from clients partition(shandong);
select * from clients partition(guangdong);
4. 組合分割槽:顧名思義,把兩種分割槽方法用到同一段分割槽建立語句中;Oracle在執行時會先對第一個分割槽鍵值用第一種分割槽方法進行分配,然後再按照第二種分割槽方法對分割槽內的資料進行二次分割槽
例1:建立人員資訊表person2,根據編號為其建立3個範圍分割槽,再在每個分割槽內根據姓名建立兩個Hash子分割槽
create table person2 --建立以一個描述個人資訊的表
(
id number primary key, --個人的編號
name varchar2(20), --姓名
sex varchar2(2) --性別
)
partition by range(id)--以id作為分割槽鍵建立範圍分割槽
subpartition by hash(name)--以name列作為分割槽鍵建立hash子分割槽
subpartitions 2 store in(tb_3,tb_4)--hash子分割槽公有兩個,分別儲存在兩個不同的名稱空間中
(
partition par1 values less than(5000),--範圍分割槽,id小於5000
partition par2 values less than(10000),--範圍分割槽,id小於10000
partition par3 values less than(maxvalue)--範圍分割槽,id不小於10000
);
5. Interval分割槽:範圍分割槽的增強功能,只有最開始的分割槽是永久分割槽。隨著資料的增加會分配更多的部分、並自動建立新的分割槽和本地索引。*關於什麼是本地索引,可以參考:http://blog.csdn.net/tannafe/article/details/4132858
例1:建立銷售記錄表saleRecord,為該表建立Interval分割槽
create table saleRecord
(
id number primary key, --編號
goodsname varchar2(50),--商品名稱
saledate date,--銷售日期
quantity number--銷售量
)
partition by range(saledate)
interval (numtoyminterval(1,'year'))--按年份自動分割槽
(
--設定分割槽鍵值日期小於2012-01-01
partition par_fist values less than (to_date('2012-01-01','yyyy-mm-dd'))
);
*對於已經進行了範圍分割槽的表格,可以通過使用alter table命令的set interval選項擴充套件為Interval分割槽表,以最一開始建立的分割槽表ware_retail_part為例:
alter table ware_retail_partset interval(NUMTOYMINTERVAL(3,'month'));
*表分割槽策略:
(1)識別大表:
已經投入使用的系統,可以用analyze table語句進行分析;以上述CLIENTS表為例:
analyze table clients compute statistics;
select * from user_tables where table_name ='CLIENTS';
(更詳細的可以參考:http://blog.csdn.net/victory_xing126/article/details/44948521)
如果是研發中的系統,則要靠架構人員和客戶的實際情況進行預估。
(2)根據大表的用途,確定分割槽方法(也就是上面說的範圍分割槽、Hash分割槽、List分割槽,還是Interval分割槽);
(3)分割槽的表空間規劃
三、管理表分割槽
1. 為一個已存在的分割槽表新增新的表分割槽
例:向上面的 clients表中新增一個省份為河北省的表分割槽:
alter table clients
add partition hebei values('河北省')
storage(initial 10k next 20k) tablespace tb_3
nologging;
最後的nologging,請參考:http://blog.csdn.net/sdl_ok/article/details/5474774
2. 合併分割槽:合併分割槽時,Oracle會自動:
·將待刪除的分割槽內容挪到其他保留分割槽中;
·將待刪除分割槽的內容和索引完全清楚;
·將一個或多個索引的本地索引分割槽標識為不可用(Unsable);
·對不可用的索引進行重建
(1)合併雜湊 分割槽:也就是將一個分割槽表的所有分割槽合併
alter table person coalesce partition;
(2)合併複合分割槽:也就是把若干個分割槽合併到其他保留子分割槽中:
比如,要將person2 的par3 分割槽合併到其他分割槽中:
alter table person2 modify partition par3 coalesce subpartition;
*注:這裡說下如何檢視一個表是否是分割槽表
先檢視:
select tablespace_name from user_tables where table_name ='CLIENTS'
如果tablespace_name 為空,則表示這張表為分割槽表(當然,如果你把這張表的所有分割槽都建在同一個表空間上,那這個地方也會有值,這時就用下面的語句進行查詢)
每張表的分割槽資訊都存放在下列表中:
SELECT * FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = 'CLIENTS'
3. 刪除分割槽:可以從範圍分割槽和複合分割槽中刪除分割槽;但雜湊分割槽和複合分割槽中的雜湊子分割槽,只能通過合併來達到刪除的目的
(1)刪除一個表分割槽:刪除後該分割槽的資料記錄也會被刪除,所以操作要謹慎。
alter table ware_retail_part drop partition par_03;
如果該表存在索引,那麼需要重建該表的索引:
alter index ware_index rebuild;
*注:oracle不允許刪除最後一個表分割槽,此外,如果該表的索引是範圍分割槽的全域性索引,那麼需要重建所有索引的分割槽:
alter index ware_index rebuild index_01;
alter index ware_index rebuild index_02;
alter index ware_index rebuild index_04;
(2)先用DELETE刪除表分割槽中的資料,然後在刪除對應的分割槽,這樣做的目的是讓分割槽表的索引自動更新,即:
delete from tablename where [condition] ; --這裡的condition注意,要恰好能將分割槽表中的資料清空
commit;
alter table ware_retail_part drop partition par_03;
(3)刪除具有完整性約束的分割槽,這裡提供兩種辦法:
·先禁用約束,然後刪除該表的分割槽,在啟用約束條件:
alter table table_name disable constraints constraints_name;
注:檢視該表的約束條件語句:select constraint_name from USER_CONSTRAINTS where table_name=‘tablename’;
檢視該表的具體哪一列被設定了約束:select * from USER_CONS_COLUMNS where table_name=‘tablename’;
alter table table_name drop partition partition_name;
alter table table_name enable constraints constraints_name;
·第二種辦法:先刪除待刪除分割槽中的資料,然後在刪除分割槽:
delete from tablename where [condition] ; --這裡的condition注意,要恰好能將分割槽表中的資料清空
commit;
alter table ware_retail_part drop partition par_03;
4. 併入分割槽:·可以將兩個相鄰的範圍分割槽合併為一個新分割槽,這個新分割槽繼承原來兩個分割槽的邊界;
·如果原分割槽存在索引,則在合併時刪除索引;
·如果被合併的分割槽為空,則新生成的分割槽表示為unsable;
·不能對HASH分割槽表執行合併操作;
例:建立銷售記錄表sales,以銷售日期(季度)分為4個範圍分割槽:
create table sales--建立一個銷售記錄表
(
id number primary key,--記錄編號
goodsname varchar2(10),--商品名
saledate date--銷售日期
)
partition by range(saledate)--按照日期分割槽
(
--第一季度資料
partition part_sea1 values less than(to_date('2011-04-01','yyyy-mm-dd')) tablespace tb_3,
--第二季度資料
partition part_sea2 values less than(to_date('2011-07-01','yyyy-mm-dd')) tablespace tb_4,
--第三季度資料
partition part_sea3 values less than(to_date('2011-10-01','yyyy-mm-dd')) tablespace tb_3,
--第四季度資料
partition part_sea4 values less than(to_date('2012-01-01','yyyy-mm-dd')) tablespace tb_4
);
在sales表中建立區域性索引:
create index index_3_4 on sales(saledate)
local(
partition part_seal tablespace tb_3,
partition part_sea2 tablespace tb_4,
partition part_sea3 tablespace tb_3,
partition part_sea4 tablespace tb_4
);
將第三個分割槽併入第四個分割槽:
alter table sales merge partitions part_sea3,part_sea4 into partition part_sea4;
重建區域性索引:
alter table sales modify partition part_sea4 rebuild unusable local indexes;
四、索引分割槽
如果索引對應的表資料量很大,那麼索引佔用的空間也會很大,這是,需要對索引進行分割槽。
·本地索引:不反應基礎表的結構,只能進行範圍分割槽;
·全域性索引:能夠反映基礎表的結構,當表被更改時,oracle會自動對本地索引所在的分割槽進行維護
1. 本地索引分割槽:通過和範圍分割槽相同的列進行索引分割槽,也就是說,資料分割槽和索引分割槽是一一對應的,它有以下幾個優點:
·如果只有一個分割槽需要維護,則只有一個本地索引受影響;
·支援分割槽獨立性;
·只有本地索引能夠支援單一分割槽的裝入和解除安裝;
·表分割槽和各自的本地索引可以同時恢復;
·本地索引可以單獨重建;
·點陣圖索引僅由本地索引支援
(1)建立範圍分割槽的本地索引分割槽:
--準備表空間
create tablespace TEST_2 datafile 'C:\tsdbf\ts1.dbf'
size 10m
extent management local autoallocate;
create tablespace ts_2 datafile 'C:\tsdbf\ts2.dbf'
size 10m
extent management local autoallocate;
create tablespace tb_3 datafile 'C:\tsdbf\ts3.dbf'
size 10m
extent management local autoallocate;
--建立分割槽表:
create table studentgrade
(
id number primary key,--記錄id
name varchar2(10),--學生名稱
subject varchar2(10),--學科
grade number --成績
)
partition by range(grade)
(
--小於60分,不及格
partition par_nopass values less than(60) tablespace TEST_2,
--小於70分,及格
partition par_pass values less than(70) tablespace ts_2,
--大於或等於70分,優秀
partition par_good values less than(maxvalue) tablespace tb_3
);
--建立本地索引分割槽
create index grade_index on studentgrade(grade)
local
(
partition p1 tablespace TEST_2,
partition p2 tablespace ts_2,
partition p3 tablespace tb_3
);
--檢視索引分割槽資訊
select partition_name,tablespace_name from dba_ind_partitions where index_name = 'GRADE_INDEX';
(2)建立組合分割槽的本地分割槽索引
--建立範圍-列表組合分割槽表:
create table studentgrade2
(
id number primary key,--記錄id
name varchar2(10),--學生名稱
subject varchar2(10),--學科
grade number --成績
)
partition by range(grade)
subpartition by list(subject)
(
--小於60分,不及格
partition grade_nopass values less than ('60') tablespace ts_2
(
subpartition list1 values('math') tablespace ts_2,
subpartition list2 values('ch') tablespace tb_3,
subpartition list3 values('phy') tablespace test_2
)
,
--小於75分,及格
partition grade_pass values less than ('75')tablespace TEST_2
(
subpartition list4 values('math') tablespace ts_2,
subpartition list5 values('ch') tablespace tb_3,
subpartition list6 values('phy') tablespace test_2
)
,
--大於75分,優秀
partition grade_good values less than (maxvalue) tablespace tb_3
(
subpartition list7 values('math') tablespace ts_2,
subpartition list8 values('ch') tablespace tb_3,
subpartition list9 values('phy') tablespace test_2
)
);
--建立組合分割槽的、包含索引子分割槽的本地分割槽索引
create index subject_index on studentgrade2(subject)
local
(
partition p1 tablespace TEST_2
(
subpartition p11 tablespace test_2,
subpartition p12 tablespace test_2,
subpartition p13 tablespace test_2
)
,
partition p2 tablespace ts_2
(
subpartition p21 tablespace ts_2,
subpartition p22 tablespace ts_2,
subpartition p23 tablespace ts_2
)
,
partition p3 tablespace tb_3
(
subpartition p31 tablespace tb_3,
subpartition p32 tablespace tb_3,
subpartition p33 tablespace tb_3
)
);
*注:索引的子分割槽數必須與基礎表的子分割槽數相等,否則會報ORA-14186錯誤
2. 建立全域性索引分割槽:當分割槽中出現許多事物並且要保證所有分割槽中的資料記錄唯一時、採用這種索引;他的分割槽鍵不一定非要和表分割槽的分割槽鍵一致。
(1)建立範圍分割槽的全域性索引:
create index index_studentgrade on studentgrade(subject)
global partition by range(subject)--注意關鍵字global
(
partition p1 values less than(30),
partition p2 values less than(60),
partition p3 values less than (maxvalue)
);
(2)建立組合分割槽的全域性分割槽索引:
--建立範圍-列表組合分割槽表
create table studentgrade3
(
id number primary key,--記錄id
name varchar2(10),--學生名稱
subject varchar2(10),--學科
grade number --成績
)
partition by range(grade)
subpartition by list(subject)
(
--小於60分,不及格
partition grade_nopass values less than ('60') tablespace ts_2
(
subpartition list1 values('math') tablespace ts_2,
subpartition list2 values('ch') tablespace tb_3,
subpartition list3 values('phy') tablespace test_2
),
--小於75分,及格
partition grade_pass values less than ('75') tablespace TEST_2
(
subpartition list4 values('math') tablespace ts_2,
subpartition list5 values('ch') tablespace tb_3,
subpartition list6 values('phy') tablespace test_2
),
--大於75分,優秀
partition grade_good values less than (maxvalue) tablespace tb_3
(
subpartition list7 values('math') tablespace ts_2,
subpartition list8 values('ch') tablespace tb_3,
subpartition list9 values('phy') tablespace test_2
)
);
--建立包含子分割槽的全域性分割槽索引<strong>(這段有問題、還在鑽研中...希望有看到的大神賜教)</strong>
create index index_studentgrade3 on studentgrade3(grade,subject)
global partition by range(grade)
global subpartition by list(subject)
(
partition p1 values less than(30)
(
subpartition p11 values('math') tablespace ts_2,
subpartition p12 values('ch') tablespace tb_3,
subpartition p13 values('phy') tablespace test_2
)
,
partition p2 values less than(50)
(
subpartition p21 values('math') tablespace ts_2,
subpartition p22 values('ch') tablespace tb_3,
subpartition p23 values('phy') tablespace test_2
)
,
partition p3 values less than (maxvalue)
(
subpartition p31 values('math') tablespace ts_2,
subpartition p32 values('ch') tablespace tb_3,
subpartition p33 values('phy') tablespace test_2
)
);
例2:對上面的studentgrade表的name列建立hash分割槽的全域性索引:
create index ind_studentgrade on studentgrade(name) global partition by hash(name);
3. 管理索引分割槽:
實際操作:
--更名,範圍分割槽的全域性索引index_studentgrade下的p2分割槽
alter index index_studentgrade rename partition p2 to p2new;
--更名,組合分割槽的區域性索引subject_index下的p11子分割槽
alter index subject_index rename subpartition p11 to p11new;
--重建,區域性索引分割槽
alter index grade_index rebuild partition p1;
--重建,組合分割槽的區域性索引分割槽
alter index subject_index rebuild partition p1;
ORA-14287: 不能 REBUILD (重建) 組合範圍分割槽的索引的分割槽;這個和書上講的不一致,研究中...
--重建,組合分割槽的區域性索引子分割槽
alter index subject_index rebuild subpartition p11;
--刪除全域性索引分割槽:
alter index index_studentgrade drop partition p1;
--分割表分割槽:
ALTER TABLE table_name SPLIT partition partition_name AT (分割點) INTO (PARTITION new_partition_name1 TABLESPACE ts1,PARTITIONnew_partition_name2 TABLESPACE ts2)
;
比如:
alter table studentgrade split partition par_good at (100) into (partition par_hun tablespace ts_2, partition par_error tablespace tb_3);
--分割全域性分割槽索引:
alter index index_studentgrade split partition p2 at(40) into(partition par2_39 tablespace ts_2, partition par2_41 tablespace tb_3);
*注:如果要對maxvalue值所在的索引分割槽進行分割,則要先新增一個maxvalue分割槽,否則會報ORA-14080錯誤