Oracle_高級功能(6) 分區
oracle分區表
1.分區表:
當表中的數據量不斷增大,查詢數據的速度就會變慢,應用程序的性能就會下降,這時就應該考慮對表進行分區。
表進行分區後,邏輯上表仍然是一張完整的表,只是將表中的數據在物理上存放到多個表空間(物理文件上),
這樣查詢數據時,不至於每次都掃描整張表。
2.表分區的具體作用
Oracle的表分區功能通過改善可管理性、性能和可用性,從而為各式應用程序帶來了極大的好處。
通常,分區可以使某些查詢以及維護操作的性能大大提高。
此外,分區還可以極大簡化常見的管理任務,分區是構建千兆字節數據系統或超高可用性系統的關鍵工具。
每個分區有自己的名稱,還可以選擇自己的存儲特性。
這就使數據庫管理員在管理分區後的對象時有相當大的靈活性。
但是,從應用程序的角度來看,分區後的表與非分區表完全相同,使用sql dml命令訪問分區後的表時,無需任何修改。
什麽時候使用分區表?
1、表的大小超過2GB。
2、表中包含歷史數據,新的數據被增加到新的分區中。
3.表分區的優缺點
優點:
改善查詢性能:對分區對象的查詢可以僅搜索自己關心的分區,提高檢索速度。
增強可用性:如果表的某個分區出現故障,表在其他分區的數據仍然可用;
維護方便:如果表的某個分區出現故障,需要修復數據,只修復該分區即可;
缺點:
分區表相關:已經存在的表沒有方法可以直接轉化為分區表。
4.表分區的幾種類型及操作方法
4.1 範圍分區:
範圍分區將數據基於範圍映射到每一個分區,這個範圍是在創建分區時指定的分區鍵決定的。
當使用範圍分區時,請考慮以下幾個規則:
每一個分區都必須有一個values less then子句,它指定了一個不包括在該分區中的上限值。
所有分區,除了第一個,都會有一個隱式的下限值,這個值就是此分區的前一個分區的上限值。
在最高的分區中,maxvalue被定義。MAXVALUE代表了一個不確定的值。
例1:
假設有一個顧客表,表中有數據200行,將此表通過c_id進行分區,每個分區存儲100行,
並且每個分區保存到單獨的表空間中,這樣數據文件就可以跨越多個物理磁盤。
create table part_range1
(
c_id number primary key,
name varchar2(30),
phone varchar2(15),
email varchar2(80),
status varchar2(1)
)
partition by range (c_id)
(
partition cus_part1 values less than (101) tablespace USERS,
partition cus_part2 values less than (201) tablespace TS_FIND
);
insert into part_range1 (c_id,name) values (1,‘name‘);
insert into part_range1 (c_id,name) values (100,‘name‘);
insert into part_range1 (c_id,name) values (101,‘name‘);
insert into part_range1 (c_id,name) values (200,‘name‘);
select * from part_range1;
select * from part_range1 partition (cus_part1);
select * from part_range1 partition (cus_part2);
insert into part_range1 (c_id,name) values (201,‘name‘);
給part_range1增加分區:
alter table part_range1 add partition cus_part3 values less than (301) tablespace ts_find;
例2:使用maxvalue擴展例1。
create table part_range2
(
c_id number primary key,
name varchar2(30),
phone varchar2(15),
email varchar2(80),
status varchar2(1)
)
partition by range (c_id)
(
partition cus_part1 values less than (101) tablespace USERS,
partition cus_part2 values less than (201) tablespace TS_FIND,
partition cus_part3 values less than (maxvalue) tablespace TS_FIND
);
insert into part_range2 (c_id,name) values (201,‘name‘);
insert into part_range2 (c_id,name) values (9999,‘name‘);
select * from part_range2;
select * from part_range2 partition (cus_part3);
註意:範圍分區表使用了maxvalue後將不能在增加分區。
例3:銷售訂單表,按時間範圍分區
create table part_range3
(
order_id number(7) not null primary key,
order_date date,
total_amount number,
custotmer_id number(7)
)
partition by range (order_date)
(
partition month01 values less than (to_date(‘2017-2-1‘,‘yyyy-mm-dd‘)) tablespace users,
partition month02 values less than (to_date(‘2017-3-1‘,‘yyyy-mm-dd‘)) tablespace ts_find,
partition month03 values less than (to_date(‘2017-4-1‘,‘yyyy-mm-dd‘)) tablespace ts_find
);
partition by range (order_date)
(
partition year15 values less than (to_date(‘2016-1-1‘,‘yyyy-mm-dd‘)) tablespace users,
partition year16 values less than (to_date(‘2017-1-1‘,‘yyyy-mm-dd‘)) tablespace ts_find,
partition year17 values less than (to_date(‘2018-1-1‘,‘yyyy-mm-dd‘)) tablespace ts_find
);
4.2 列表分區:
該分區的特點是基於某個特定取值的列的取值來分區。
例1:問題投訴表,根據問題狀態分區,狀態取值:‘active‘,‘inactive‘
create table part_list1
(
problem_id number(7) not null primary key,
description varchar2(2000),
customer_id number(7),
date_entered date,
status varchar2(20)
)
partition by list (status)
(
partition active values (‘active‘) tablespace users,
partition inactive values (‘inactive‘) tablespace ts_find
);
--測試
insert into part_list1 (problem_id,status) values (11,‘active‘);
insert into part_list1 (problem_id,status) values (12,‘inactive‘);
select * from part_list1;
select * from part_list1 partition (active);
select * from part_list1 partition (inactive);
例2:北京人口,按行政區劃分區
create table part_list2
(
id number(8) primary key ,
name varchar (20),
area varchar (10)
)
partition by list (area)
(
partition area01 values (‘東城‘,‘西城‘) tablespace users,
partition area02 values (‘海澱‘,‘昌平‘) tablespace ts_find
);
例3:按照余數分區--不支持
create table part_list3
(
id number(8) not null primary key,
des varchar2(2000)
)
partition by list (mod(id,3))
(
partition p1 values (0) tablespace users,
partition p2 values (1) tablespace ts_find,
partition p3 values (2) tablespace ts_find
);
4.3 散列分區:
在列值上使用散列算法,以確定將行放入哪個分區中。
當列的值沒有合適的條件時,建議使用散列分區。
散列分區是通過指定分區編號來均勻分布數據的一種分區類型
(分區個數應該是2的次方,否則分布不均勻)。
hash分區最主要的機制是根據hash算法來計算具體某條紀錄應該插入到哪個分區中。
例1:2個分區
create table part_hash1
(
col number(8),
inf varchar2(100)
)
partition by hash (col)
(
partition p1 tablespace users,
partition p2 tablespace ts_find
);
insert into part_hash1 values (1,‘b‘);
insert into part_hash1 values (2,‘b‘);
insert into part_hash1 values (3,‘b‘);
insert into part_hash1 values (4,‘b‘);
insert into part_hash1 values (5,‘b‘);
insert into part_hash1 values (6,‘b‘);
insert into part_hash1 values (7,‘b‘);
insert into part_hash1 values (8,‘b‘);
select * from part_hash1;
select * from part_hash1 partition(p1);
select * from part_hash1 partition(p2);
例2:僅指定分區個數的簡單寫法,分區名由系統指定
create table part_hash2
(
empno number (4),
ename varchar2 (30),
sal number
)
partition by hash (empno) partitions 4
store in (users,ts_find);
--查看系統指定的分區名
select * from user_tab_partitions where table_name=‘PART_HASH2‘;
--復制數據
insert into part_hash2 select empno,ename,sal from emp;
select * from part_hash2;
select * from part_hash2 partition(SYS_P42);
好處:
對於分區本身不需要定期的進行分區加入(範圍分區和LIST分區需要定期的對新加入的值新建分區)
可以消除訪問熱點塊及索引熱點塊,由於索引是排序後的結構,對於一列自增的列加入範圍分區,
可能對索引的高位塊進行頻繁的數據插入,導致頻繁的寫入和分裂。
對於這樣的索引如果加入散列分區索引即可消除。
限制:
分區不能太多,典型的大約1000個分區,那麽在分區觸發(謂詞導致索引範圍掃描)的並行訪問操作時可能更慢,
因為有非常多額外的分區維護操作。
對於長期使用範圍掃描的字段不適合散列分區,因為這樣會導致多個分區掃描,而對於經常唯一掃描的字段適合建立HASH分區。
4.4 組合範圍列表分區:(範圍+列表分區)
這種分區是基於範圍分區和列表分區,表首先按某列進行範圍分區,
然後再按某列進行列表分區,分區之中的分區被稱為子分區。
create table part_range_list
(
product_id varchar2(5),
sales_date date,
sales_cost number(10),
status varchar2(20)
)
partition by range(sales_date) subpartition by list (status)
(
partition p1 values less than(to_date(‘2017-02-01‘,‘yyyy-mm-dd‘)) tablespace users
(
subpartition p1sub1 values (‘active‘) tablespace users,
subpartition p1sub2 values (‘inactive‘) tablespace users
),
partition p2 values less than (to_date(‘2017-03-01‘,‘yyyy-mm-dd‘)) tablespace ts_find
(
subpartition p2sub1 values (‘active‘) tablespace ts_find,
subpartition p2sub2 values (‘inactive‘) tablespace ts_find
)
);
insert into part_range_list (product_id,sales_date,status) values (1,sysdate-480,‘active‘);
insert into part_range_list (product_id,sales_date,status) values (2,sysdate-481,‘inactive‘);
insert into part_range_list (product_id,sales_date,status) values (3,sysdate-451,‘active‘);
insert into part_range_list (product_id,sales_date,status) values (4,sysdate-450,‘inactive‘);
select * from part_range_list;
select * from part_range_list partition (p1);
select * from part_range_list partition (p2);
select * from part_range_list subpartition (p1sub1);
select * from part_range_list subpartition (p1sub2);
select * from part_range_list subpartition (p2sub1);
select * from part_range_list subpartition (p2sub2);
4.5 復合範圍散列分區:(範圍+散列分區)
這種分區是基於範圍分區和散列分區,
表首先按某列進行範圍分區,然後再按某列進行散列分區。
create table part_range_hash
(
transaction_id number primary key,
item_id number(8) not null,
item_description varchar2(300),
transaction_date date
)
partition by range(transaction_date) subpartition by hash(transaction_id)
subpartitions 2 store in (users,ts_find)
(
partition part_01 values less than(to_date(‘2017-01-01‘,‘yyyy-mm-dd‘)),
partition part_02 values less than(to_date(‘2018-01-01‘,‘yyyy-mm-dd‘))
);
5.分區相關數據字典
--查詢所有的的分區表
select * from user_tables a where a.partitioned=‘YES‘
--顯示分區表信息:
select * from dba_part_tables;
select * from all_part_tables;
select * from user_part_tables;
--顯示分區信息:
select * from dba_tab_partitions
select * from all_tab_partitions
select * from user_tab_partitions
--顯示子分區信息
select * from dba_tab_subpartitions
select * from all_tab_subpartitions
select * from user_tab_subpartitions
--顯示分區列信息:
select * from dba_part_key_columns
select * from all_part_key_columns
select * from user_part_key_columns
--顯示子分區列信息:
select * from dba_subpart_key_columns
select * from all_subpart_key_columns
select * from user_subpart_key_columns
6.表分區相關操作:
6.1 添加分區
給part_range1增加分區:
alter table part_range1 add partition cus_part3 values less than (301) tablespace ts_find;
insert into part_range1 (customer_id,name) values (201,‘name‘);
註意:以上添加的分區界限應該高於最後一個分區界限。
給part_range2增加分區:maxvalue
alter table part_range2 add partition cus_part4 values less than (301) tablespace ts_find;
--ORA-14074: 分區界限必須調整為高於最後一個分區界限
給組合範圍列表分區part_range_list增加分區
alter table part_range_list add partition p3
values less than (to_date(‘2017-4-1‘,‘yyyy-mm-dd‘)) tablespace ts_find;
--查看
select * from user_part_tables where table_name=‘PART_RANGE_LIST‘;
select * from user_tab_partitions where table_name=‘PART_RANGE_LIST‘; --默認生成了一個子分區
select * from user_tab_subpartitions where table_name=‘PART_RANGE_LIST‘; --子分區名:SYS_SUBP65
select * from user_part_key_columns where name=‘PART_RANGE_LIST‘;
select * from user_subpart_key_columns where name=‘PART_RANGE_LIST‘;
檢查發現p3有一個子分區,並且子分區的鍵值是DEFAULT,插數據驗證:
insert into part_range_list (product_id,sales_date,sales_cost,status) values (111,to_date(‘2017-03-31‘,‘yyyy-mm-dd‘),1,‘active‘);
insert into part_range_list (product_id,sales_date,sales_cost,status) values (112,to_date(‘2017-03-31‘,‘yyyy-mm-dd‘),1,‘inactive‘);
select * from part_range_list;
select * from part_range_list partition(p3);
select * from part_range_list subpartition(SYS_SUBP49);
6.2 添加子分區
part_range_list表的p3分區添加子分區(要求:與P1子分區的鍵值一致)
alter table part_range_list modify partition p3 add subpartition p3sub1 values(‘active‘);
alter table part_range_list modify partition p3 add subpartition p3sub2 values(‘inactive‘);
--ORA-14621: 在 DEFAULT 子分區已存在時無法添加子分區
6.3 刪除(DEFAULT)子分區:
alter table part_range_list drop subpartition SYS_SUBP49;
--ORA-14629: 無法刪除一個分區中唯一的子分區
6.4 無法刪除一個分區中唯一的子分區時將分區刪除
alter table part_range_list drop partition p3;
6.5 正確的添加組合分區的方式:添加組合分區時將子分區一並添加
alter table part_range_list add partition p3 values less than (to_date(‘2017-4-1‘,‘yyyy-mm-dd‘)) tablespace ts_find
(subpartition p3sub1 values (‘active‘) tablespace ts_find,
subpartition p3sub2 values (‘inactive‘) tablespace ts_find);
--驗證
insert into part_range_list (product_id,sales_date,sales_cost,status)
values (111,to_date(‘2017-03-31‘,‘yyyy-mm-dd‘),1,‘active‘);
insert into part_range_list (product_id,sales_date,sales_cost,status)
values (112,to_date(‘2017-03-31‘,‘yyyy-mm-dd‘),1,‘inactive‘);
select * from part_range_list;
select * from part_range_list partition(p3);
select * from part_range_list subpartition(p3sub1);
6.6 刪除子分區
alter table part_range_list drop subpartition p3sub1;
--alter table part_range_list drop subpartition p3sub2;
6.7 刪除分區:
alter table part_range_list drop partition p3;
alter table part_range_list drop partition p2;
alter table part_range_list drop partition p1;
--ORA-14083: 無法刪除分區表的唯一分區
如果刪除的分區是表中唯一的分區,那麽此分區將不能被刪除,要想刪除此分區,必須刪除表。
drop table part_range_list;
6.8 截斷分區
截斷某個分區是指刪除某個分區中的數據,並不會刪除分區,也不會刪除其它分區中的數據。
當表中即使只有一個分區時,也可以截斷該分區。
--再創建分區表part_range_list,並插入數據
insert into part_range_list (product_id,sales_date,sales_cost,status) values (111,to_date(‘2017-02-21‘,‘yyyy-mm-dd‘),1,‘active‘);
insert into part_range_list (product_id,sales_date,sales_cost,status) values (112,to_date(‘2017-02-21‘,‘yyyy-mm-dd‘),1,‘inactive‘);
select * from part_range_list;
select * from part_range_list partition(p2);
select * from part_range_list subpartition(p2sub1);
select * from part_range_list subpartition(p2sub2);
截斷子分區:
alter table part_range_list truncate subpartition p2sub2;
截斷分區:
alter table part_range_list truncate partition p2;
6.9 合並分區
合並分區是將相鄰的分區合並成一個分區,結果分區將采用較高分區的界限。
註意:不能將分區合並到界限較低的分區。
select * from user_part_tables where table_name=‘PART_RANGE1‘;
select * from user_tab_partitions where table_name=‘PART_RANGE1‘;
select * from user_part_key_columns where name=‘PART_RANGE1‘;
select * from part_range1;
select * from part_range1 partition(cus_part1);
select * from part_range1 partition(cus_part2);
select * from part_range1 partition(cus_part3);
合並分區:
alter table part_range1 merge partitions cus_part1,cus_part2 into partition cus_part2;
--alter table part_range1 merge partitions cus_part3,cus_part2 into partition cus_part2;
ORA-14273: 必須首先指定下界分區
--alter table part_range1 merge partitions cus_part2,cus_part3 into partition cus_part2;
ORA-14275: 不能將下界分區作為結果分區重用
6.10 拆分分區
拆分分區將一個分區拆分兩個新分區,拆分後原來分區不再存在。
alter table part_range1 split partition cus_part2 at(101) into (partition p1,partition p2);
--驗證
select * from user_part_tables where table_name=‘PART_RANGE1‘;
select * from user_tab_partitions where table_name=‘PART_RANGE1‘;
select * from user_part_key_columns where name=‘PART_RANGE1‘;
select * from part_range1 partition(p1);
select * from part_range1 partition(p2);
select * from part_range1 partition(cus_part3);
註意:不能對hash類型的分區進行拆分。
select * from user_part_tables where table_name=‘PART_HASH1‘;
select * from user_tab_partitions where table_name=‘PART_HASH1‘;
select * from user_part_key_columns where name=‘PART_HASH1‘;
select * from part_hash1 partition(p2);
alter table part_hash1 split partition p2 at(4) into (partition p3,partition p4);
--ORA-14255: 未按範圍, 列表, 組合範圍或組合列表方法對表進行分區
6.11 重命名表分區
select * from user_tab_partitions where table_name=‘PART_RANGE1‘;
alter table part_range1 rename partition cus_part3 to p3;
6.12 分區表查詢
--分區表查詢
select * from part_range1;
--單分區查詢
select * from part_range1 partition (p1);
--跨分區查詢
select * from
(select * from part_range1 partition (p1)
union all
select * from part_range1 partition (p2)
union all
select * from part_range1 partition (p3));
Oracle_高級功能(6) 分區