Oracle 11g分區技術

一、分區技術概念

分區技術(Partitioning)可以將大表、大索引分解爲更小、易於管理的塊,這些塊稱爲分區(Partition),通過分區技術可以有效的解決大表、大索引帶來的問題,對分區表執行的SQL查詢或DML語句與普通數據表的語句一樣。但是定義了分區後,DML語句可以訪問、操作一個單獨的分區,而不是整個表或索引,這樣通過分區技術就能簡化對大數據庫對象的管理工作。

使用分區技術,有以下優勢:

  • 提高數據的可用性;
  • 將大段分解爲小段,從而減輕管理的負擔;
  • 改善某些查詢的性能(分區修剪);
  • 可以把數據的修改分佈到多個分區上,從而減少I/O競爭;

二、分區表的分類

1.範圍分區

1)範圍分區介紹

創建範圍分區的關鍵字是Range,創建該分區後,其中的數據可以根據分區鍵指定的範圍進行分佈,當數據在範圍內均勻分佈時,性能最好。

當表結構採用範圍分區時,首先要考慮分區的列應該符合範圍分區的方法;其次要考慮列的數據值的取值範圍;最後考慮列的邊界問題。

2)語法結構
在這裏插入圖片描述

3)示例

--創建範圍分區表
create table T_RANGE
(
  ID      NUMBER,
  NAME    VARCHAR2(100),
  CDATE   DATE default sysdate,
  CREATOR VARCHAR2(20) default 'system'
)
partition by range (CDATE)
(
  partition P1 values less than (TO_DATE('2018-05-21', 'YYYY-MM-DD')),
  partition P2 values less than (TO_DATE('2018-05-22', 'YYYY-MM-DD')),
  partition P3 values less than (TO_DATE('2018-05-23', 'YYYY-MM-DD')),
  partition P4 values less than (TO_DATE('2018-05-24', 'YYYY-MM-DD')),
  partition P5 values less than (maxvalue)
 
);
--創建序列
create sequence seq_range;
--初始化範圍分區表數據
insert into t_range values(seq_range.nextval,'Jack',to_date('2018-05-20', 'YYYY-MM-DD'),'system');
insert into t_range values(seq_range.nextval,'Peter',to_date('2018-05-21', 'YYYY-MM-DD'),'system');
insert into t_range values(seq_range.nextval,'Geo',to_date('2018-05-22', 'YYYY-MM-DD'),'system');
insert into t_range values(seq_range.nextval,'Lucy',to_date('2018-05-23', 'YYYY-MM-DD'),'system');
insert into t_range values(seq_range.nextval,'Smith',to_date('2018-05-24', 'YYYY-MM-DD'),'system');
insert into t_range values(seq_range.nextval,'James',to_date('2018-05-25', 'YYYY-MM-DD'),'system');
insert into t_range values(seq_range.nextval,'Tom',to_date('2018-05-26', 'YYYY-MM-DD'),'system');
commit;
--查看錶數據
select * FROM t_range;
 
select * FROM t_range partition(p1);
--查看分區信息
SELECT * FROM user_part_tables t WHERE t.table_name = 'T_RANGE';
 
SELECT * FROM User_Tab_Partitions t WHERE t.table_name='T_RANGE';
 
SELECT * FROM user_segments t WHERE t.segment_name = 'T_RANGE';

2.散列分區

1)散列分區介紹

對於散列分區表,Oracle會使用一個散列函數對每一條插入數據的分區列值計算出其散列值,以此確定數據應當放在N個分區中的哪個分區中。Oracle建議N是2的一個冪(2、4、8、16等),這樣表中的數據才能最好的分佈在所有的分區上。散列分區可用於大強度更新、具有高度爭用的環境,使用散列分區後,更新不在集中於一個熱點段中,而是分散到16個分區上,每個分區都能進行數據的修改。

2)語法結構
在這裏插入圖片描述
3)示例

--創建哈希分區表
create table T_HASH
(
  id      NUMBER,
  name    VARCHAR2(100),
  cdate   DATE default SYSDATE,
  creator VARCHAR2(100) default 'system'
)
partition by hash (ID)
(
  partition P1
    tablespace USERS,
  partition P2
    tablespace TEST
);
--創建序列
CREATE SEQUENCE seq_hash;
--初始化散列表
 BEGIN
   FOR j IN 1..10 LOOP
     INSERT INTO t_hash(ID,NAME) VALUES(seq_hash.nextval,'HASH'||j);
   END LOOP;
   COMMIT;
 END;
--查看錶數據
SELECT * FROM t_hash;
SELECT * FROM t_hash PARTITION(p1);
--查看分區信息
SELECT * FROM User_Part_Tables t WHERE t.table_name='T_HASH';
SELECT * FROM User_Tab_Partitions t WHERE t.table_name='T_HASH';
SELECT * FROM User_Segments t WHERE t.segment_name='T_HASH';

4)注意事項

  • 使用哈希分區,無法控制一行最終放在哪個分區中,Oracle會應用散列函數,並依據散列的結果來確定行會放在哪裏;
  • 改變散列分區的個數,數據會在所有分區中重新分佈,向一個散列分區表增加或刪除一個分區時,將導致所有數據都會重寫,因爲現在每一行都可能屬於一個不同的分區;
  • 分區數應該是2的冪。如果分區數是2的冪,那麼分區將會均勻分佈,如果不是,那麼分區將會不均勻分佈。

3.列表分區

1)列表分區介紹

列表分區爲每個分區指定了一個離散值列表,每行數據根據其分區鍵值所屬列表歸到相應的分區中。

2)語法結構
在這裏插入圖片描述

3)示例

--創建列表分區
create table T_LIST
(
  id      NUMBER,
  city    VARCHAR2(50),
  cdate   DATE default SYSDATE,
  creator VARCHAR2(20) default 'system'
)
partition by list (CITY)
(
  partition P1 values ('Henan'),
  partition P2 values ('Shandong'),
  partition P3 values ('Guangdong'),
  partition P4 values ('Hunan')
);
--創建序列
CREATE SEQUENCE seq_list;
--初始化數據
BEGIN
  FOR j IN 1 .. 15
  LOOP
    IF MOD(j, 5) = 1
    THEN
      INSERT INTO t_list(ID,city)VALUES(seq_list.nextval,'Henan');
    ELSIF MOD(j, 5) = 2
    THEN
      INSERT INTO t_list(ID,city)VALUES(seq_list.nextval,'Shandong');
    ELSIF MOD(j, 5) = 3
    THEN
      INSERT INTO t_list(ID,city)VALUES(seq_list.nextval,'Guangdong');
    ELSE
      INSERT INTO t_list (ID,city)VALUES(seq_list.nextval,'Hunan');
    END IF;
  END LOOP;
  COMMIT;
END;
--查看錶數據
SELECT * FROM t_list;
SELECT * FROM t_list PARTITION(p1);
--查看分區信息
SELECT * FROM User_Part_Tables t WHERE t.table_name='T_LIST';
SELECT * FROM User_Tab_Partitions t WHERE t.table_name='T_LIST';
SELECT * FROM User_Segments t WHERE t.segment_name='T_LIST';

思考:新插入一個列表中沒有的省份,會出現什麼情況?

SQL> INSERT INTO t_list (ID,city)VALUES(seq_list.nextval,'Jilin');
INSERT INTO t_list (ID,city)VALUES(seq_list.nextval,'Jilin')
                                   *
ERROR at line 1:
ORA-14400: inserted partition key does not map to any partition

解決:

SQL> alter table t_list add partition pd values(default);
 
Table altered.
 
SQL> INSERT INTO t_list (ID,city)VALUES(seq_list.nextval,'Jilin');
 
1 row created.

注:一旦列表分區表有一個Default分區,就不能再向這個表增加更多的分區了,此時必須刪除Default分區,然後再增加分區,再加回Default分區。

alter table t_list add partition p5 values('Heilongjiang');
ALTER TABLE t_list DROP PARTITION pd;
alter table t_list add partition pd values(default);

4.間隔分區

1)間隔分區介紹

間隔分區(interval partition)是Oracle 11g Release 1及以上版本纔有的特性,與範圍分區類似,使用關鍵字interval進行分區。
11g之前,維護分區需要手工。11g之後使用interval來實現自動擴展分區,簡化了維護:
根據年: INTERVAL(NUMTOYMINTERVAL(1,‘YEAR’));
根據月: INTERVAL(NUMTOYMINTERVAL(1,‘MONTH’));
根據天: INTERVAL(NUMTODSINTERVAL(1,‘DAY’));
根據時分秒: NUMTODSINTERVAL( n, { ‘DAY’|‘HOUR’|‘MINUTE’|‘SECOND’})

2)示例

--創建分區表
create table T_INTERVAL
(
  id      NUMBER,
  name    VARCHAR2(100),
  cdate   DATE default Sysdate,
  creator VARCHAR2(20) default 'system'
)
partition by range (CDATE)INTERVAL(NUMTODSINTERVAL(1,'DAY'))
(
  partition P1 values less than (TO_DATE('2018-05-22', 'YYYY-MM-DD'))
);
--創建序列
CREATE SEQUENCE seq_interval;
--初始化數據
BEGIN
  FOR j IN 1..5 LOOP
    INSERT INTO t_interval(ID,NAME,cdate) VALUES(seq_interval.nextval,'Inter '||j,SYSDATE +j);
  END LOOP;
  COMMIT;
END;
--查看數據
SELECT * FROM T_INTERVAL;
SELECT * FROM t_interval PARTITION(SYS_P41);
--查看分區信息
SELECT * FROM User_Part_Tables t WHERE t.table_name='T_INTERVAL';
SELECT * FROM User_Tab_Partitions t WHERE t.table_name='T_INTERVAL';
SELECT * FROM User_Segments t WHERE t.segment_name='T_INTERVAL';

5.組合分區

1)組合範圍分區
在這裏插入圖片描述

2)組合列表分區
在這裏插入圖片描述

3)組合哈希分區
在這裏插入圖片描述

三、索引分區

1 本地前綴分區索引

1)解釋本地和前綴
本地:所謂本地指索引的分區方法和對應表的分區方法一樣;
前綴索引:所謂前綴索引是指分區字段是索引字段的前綴。

2)創建本地前綴分區索引

CREATE INDEX idx_range_cdate ON t_range(cdate) LOCAL;
CREATE INDEX idx_range_cdate_name ON t_range(cdate,NAME) LOCAL;

3)查看分區索引信息

SELECT * FROM User_Part_Indexes t WHERE t.table_name='T_RANGE';
SELECT * FROM user_ind_partitions t WHERE t.index_name='IDX_RANGE_CDATE';

4)優點
使用本地前綴分區索引查詢數據時,往往會極大提高查詢性能,因爲這樣的查詢會首先鎖定一個索引分區,這樣就比使用一個大索引減少了查詢時間,而後通過分區索引定位表分區,繼而找到需要的數據;
表分區被刪除或合併後,Oracle將自動維護索引分區,使得本地前綴分區索引依然有效,從而提高表的可用性。

2 本地非前綴分區索引

1)說明

本地非前綴分區索引與本地前綴分區索引的差異就在於分區索引的前綴字段,如果創建的本地分區索引不使用表分區的分區鍵作爲前綴就是本地非前綴分區索引。

2)創建索引

CREATE INDEX idx_range_name ON t_range(NAME) LOCAL;

3)查看索引信息

SELECT * FROM User_Part_Indexes t WHERE t.table_name='T_RANGE';
SELECT * FROM user_ind_partitions t WHERE t.index_name='IDX_RANGE_NAME';

4)優點
當執行查詢時,Oracle會檢索所有的索引分區。提高了索引訪問的可用性,即在表分區被drop或merge後,本地非前綴分區索引依然有效。
注:如果歷史數據整理很頻繁,不能承受全局分區索引重建的長時間等待,則最好使用本地非前綴分區索引。

3 全局分區索引

1)說明

全局的含義是索引的分區和表的分區沒有關係。全局分區索引有兩種類型,一種是全局範圍分區索引,一種是全局哈希分區索引。全局範圍分區索引使用某個字段作爲分區鍵,可以有效控制索引的分佈;全局哈希分區索引的創建由Oracle自動完成,適用於大併發量和批量數據加載的情況。

2)創建索引

CREATE INDEX idx_range_id ON t_range(ID) 
GLOBAL PARTITION BY HASH(ID)
(
PARTITION p1,
PARTITION p2,
PARTITION p3,
PARTITION p4
);

3)查看索引信息

SELECT * FROM User_Part_Indexes t WHERE t.table_name='T_RANGE';
SELECT * FROM user_ind_partitions t WHERE t.index_name='IDX_RANGE_ID';

4)缺點

如果表分區被刪除或合併,全局分區索引無效,需要重建,如果用戶的數據無法容忍在分區變動之後長時間的索引重建過程,最好不要使用全局分區索引,因爲重建索引佔用的很長時間大大降低了數據的可訪問性。

四、分區維護

1.分區前維護

1)創建分區表

CREATE TABLE t_maintain(
owner,
object_name,
object_id,
data_object_id,
object_type,
created,
last_ddl_time,
TIMESTAMP,
status)PARTITION BY RANGE(object_id)
(PARTITION p_3000 VALUES LESS THAN (3000) TABLESPACE USERS,
PARTITION p_6000 VALUES LESS THAN (6000) TABLESPACE USERS,
PARTITION p_max VALUES LESS THAN (MAXVALUE) TABLESPACE USERS
) AS
SELECT owner,
       object_name,
       object_id,
       data_object_id,
       object_type,
       created,
       last_ddl_time,
       TIMESTAMP,
       status
  FROM dba_objects;

2)查看分區信息

SELECT * FROM User_Part_Tables t WHERE t.table_name='T_MAINTAIN';
SELECT * FROM User_Tab_Partitions t WHERE t.table_name='T_MAINTAIN';
SELECT * FROM User_Segments t WHERE t.segment_name='T_MAINTAIN';

3)創建全局索引和本地前綴分區索引
對於本地分區索引不會受到表分區的變化影響,本地分區索引會自動維護;對於全局分區索引,一旦表分區變化則失效,需要重建。

CREATE INDEX idx_maintain_owner ON t_maintain(owner) GLOBAL;
CREATE INDEX idx_maintain_objectid ON t_maintain(object_id) LOCAL;

4)查看索引狀態

SELECT * FROM User_Part_Indexes t WHERE t.table_name='T_MAINTAIN';

SELECT * FROM user_ind_partitions t WHERE t.index_name='IDX_MAINTAIN_OBJECTID';

SELECT t.index_name,t.status,t.* FROM User_Indexes t
WHERE t.table_name='T_MAINTAIN';

2.新增分區

1)新增分區
如果分區邊界不是maxvalue,則可以直接添加新的分區,否則,需刪除原有分區,再添加,或者採用分區的拆分,如果沒有刪除邊界分區而直接增加分區,則出錯。

ALTER TABLE t_maintain ADD PARTITION p_9000 VALUES LESS THAN(9000) TABLESPACE USERS;
ORA-14074: partition bound must collate higher than that of the last partition

2)刪除默認分區再增加分區

ALTER TABLE t_maintain DROP PARTITION p_max;
ALTER TABLE t_maintain ADD PARTITION p_9000 VALUES LESS THAN(9000) TABLESPACE USERS;

3)增加默認分區

ALTER TABLE t_maintain ADD PARTITION p_max VALUES LESS THAN(MAXVALUE) TABLESPACE USERS;

4)查看新增後分區信息

SELECT * FROM User_Tab_Partitions t WHERE t.table_name='T_MAINTAIN';

5)查看索引狀態

SELECT t.index_name,t.status,t.* FROM User_Indexes t
WHERE t.table_name='T_MAINTAIN';

從查詢結果可知,IDX_MAINTAIN_OWNER索引狀態不可用,所以需要重建全局索引。

6)重建索引

ALTER INDEX IDX_MAINTAIN_OWNER REBUILD;
SELECT t.index_name,t.status,t.* FROM User_Indexes t
WHERE t.table_name='T_MAINTAIN';

3.移動分區

1)移動分區
移動分區是將分區從一個表空間移動到另外一個表空間,比如當我們的一個磁盤需要更換或維修時,並且該磁盤存放了分區對象的數據,此時就可以通過移動分區將分區遷移到別的表空間。

2)創建新的表空間

CREATE TABLESPACE maintain DATAFILE '/u01/app/oracle/oradata/orcl/maintain01.dbf' SIZE 100M;

3)移動分區到新表空間

ALTER TABLE T_MAINTAIN MOVE PARTITION P_6000 TABLESPACE maintain;

4)查看分區

SELECT * FROM User_Tab_Partitions t WHERE t.table_name='T_MAINTAIN';

5)查看索引狀態

SELECT t.index_name,t.status,t.* FROM User_Indexes t
WHERE t.table_name='T_MAINTAIN';

6)重建索引

ALTER INDEX IDX_MAINTAIN_OWNER REBUILD;
SELECT t.index_name,t.status,t.* FROM User_Indexes t
WHERE t.table_name='T_MAINTAIN';

4.截斷分區

1)截斷分區
截斷(truncate)相對刪除操作很快,數據倉庫中的大量數據的批量數據加載可能會用到,截斷分區同樣會自動維護局部分區索引,同時會使全局索引不可用,所以需要重建全局分區索引。

ALTER TABLE T_MAINTAIN TRUNCATE PARTITION p_3000;

2)查看分區數據

SELECT * FROM t_maintain PARTITION(P_3000);

3)查看索引狀態

SELECT t.index_name,t.status,t.* FROM User_Indexes t
WHERE t.table_name='T_MAINTAIN';

4)重建索引

ALTER INDEX IDX_MAINTAIN_OWNER REBUILD;
SELECT t.index_name,t.status,t.* FROM User_Indexes t
WHERE t.table_name='T_MAINTAIN';

5.刪除分區

1)刪除分區
使用Drop指令直接刪除分區,依然會造成全局索引失效。

ALTER TABLE T_MAINTAIN DROP PARTITION P_6000;

2)查看分區

SELECT * FROM User_Tab_Partitions t WHERE t.table_name='T_MAINTAIN';
  1. 查看索引狀態
SELECT t.index_name,t.status,t.* FROM User_Indexes t
WHERE t.table_name='T_MAINTAIN';

4)重建索引

ALTER INDEX IDX_MAINTAIN_OWNER REBUILD;

6.拆分分區

1)拆分分區
是把一個分區拆成兩個分區,比如把p_9000分區拆爲p_6000,用戶存放object_id>=3000and object_id < 6000;p_9000用戶存放object_id>=6000and object_id < 9000的記錄,利用split技術可實現這種拆分。

DROP TABLE t_maintain;
CREATE TABLE t_maintain(
owner,
object_name,
object_id,
data_object_id,
object_type,
created,
last_ddl_time,
TIMESTAMP,
status)PARTITION BY RANGE(object_id)
(PARTITION p_3000 VALUES LESS THAN (3000) TABLESPACE USERS,
PARTITION p_9000 VALUES LESS THAN (9000) TABLESPACE USERS,
PARTITION p_max VALUES LESS THAN (MAXVALUE) TABLESPACE USERS
) AS
SELECT owner,
       object_name,
       object_id,
       data_object_id,
       object_type,
       created,
       last_ddl_time,
       TIMESTAMP,
       status
  FROM dba_objects;

2)查看分區

SELECT * FROM User_Tab_Partitions t WHERE t.table_name='T_MAINTAIN';

3)拆分分區

ALTER TABLE T_MAINTAIN SPLIT PARTITION P_9000 AT(6000) INTO (
PARTITION p_6000 TABLESPACE USERS,
PARTITION p_9000 TABLESPACE maintain);

4)再次查看分區信息

SELECT * FROM User_Tab_Partitions t WHERE t.table_name='T_MAINTAIN';

5)查詢分區的邊界

SELECT MIN(object_id),MAX(object_id) FROM t_maintain PARTITION(p_6000);

7.合併分區

1)合併分區
相鄰的分區可以合併爲一個分區,新分區的下邊界爲原來邊界值較低的分區,上邊界爲原來邊界值較高的分區,原先的局部索引相應也會合並,全局索引會失效,需重建。

ALTER TABLE T_MAINTAIN MERGE PARTITIONS p_6000,p_9000 INTO PARTITION p_9000;

2)查看分區信息

SELECT * FROM User_Tab_Partitions t WHERE t.table_name='T_MAINTAIN';

3)查看分區邊界

SELECT MIN(object_id),MAX(object_id) FROM t_maintain PARTITION(p_9000);

8.交換分區

1)交換分區

分區交換可以把一個表和分區表中的一個分區中的數據進行對換,分區的交換隻是一個數據字典的操作,因此操作速度很快。

DROP TABLE t_maintain;
CREATE TABLE t_maintain(
owner,
object_name,
object_id,
data_object_id,
object_type,
created,
last_ddl_time,
TIMESTAMP,
status)PARTITION BY RANGE(object_id)
(PARTITION p_3000 VALUES LESS THAN (3000) TABLESPACE USERS,
PARTITION p_6000 VALUES LESS THAN (6000) TABLESPACE USERS,
PARTITION p_9000 VALUES LESS THAN (9000) TABLESPACE USERS,
PARTITION p_max VALUES LESS THAN (MAXVALUE) TABLESPACE USERS
) AS
SELECT owner,
       object_name,
       object_id,
       data_object_id,
       object_type,
       created,
       last_ddl_time,
       TIMESTAMP,
       status
  FROM dba_objects;
  
ALTER TABLE  t_maintain TRUNCATE PARTITION p_6000;

2)構建一個表,表結構和分區表相同

CREATE TABLE t_6000
 AS
SELECT owner,
       object_name,
       object_id,
       data_object_id,
       object_type,
       created,
       last_ddl_time,
       TIMESTAMP,
       status
  FROM dba_objects t
  WHERE t.object_id>=3000 AND t.object_id<6000;

3)使用Exchange指令交換分區

ALTER TABLE t_maintain EXCHANGE PARTITION p_6000 WITH TABLE t_6000;

4)查看分區p_6000

SELECT COUNT(1) FROM t_maintain PARTITION (p_6000);

5)驗證原表t_6000沒有數據

SELECT COUNT(1) FROM t_6000;

注:如果交換的表中包含的記錄不符合分區的規定,可以使用without validation字句跳過檢查,具體參照下面的演示:

ALTER TABLE  t_maintain TRUNCATE PARTITION p_6000; 
DROP TABLE t_6000;
CREATE TABLE t_6000
 AS
SELECT owner,
       object_name,
       object_id,
       data_object_id,
       object_type,
       created,
       last_ddl_time,
       TIMESTAMP,
       status
  FROM dba_objects t
  WHERE t.object_id>=3000 AND t.object_id<7000;
ALTER TABLE t_maintain EXCHANGE PARTITION p_6000 WITH TABLE t_6000;
ORA-14099: all rows in table do not qualify for specified partition
ALTER TABLE t_maintain EXCHANGE PARTITION p_6000 WITH TABLE t_6000 WITHOUT validation;
SELECT COUNT(1) FROM t_maintain PARTITION (p_6000);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章