分區表的概念:
當表中的數據量不斷增大,查詢數據的速度就會變慢,應用程序的性能就會下降,這時就應該考慮對表進行分區。表進行分區后,邏輯上表仍然是一張完整的表,只是將表中的數據在物理上存放到多個表空間(物理文件上),這樣查詢數據時,不至於每次都掃描整張表。
分區表的優點:
1) 改善查詢性能:對分區對象的查詢可以僅搜索自己關心的分區,提高檢索速度。
2) 增強可用性:如果表的某個分區出現故障,表在其他分區的數據仍然可用;
3) 維護方便:如果表的某個分區出現故障,需要修復數據,只修復該分區即可;
4) 均衡I/O:可以把不同的分區映射到磁盤以平衡I/O,改善整個系統性能。
分區表的種類:
1.范圍分區
概念: 范圍分區將數據基於范圍映射到每一個分區,這個范圍是你在創建分區時指定的分區鍵決定的。這種分區方式是最為常用的,並且分區鍵經常采用日期。舉個例子:你可能會將銷售數據按照月份進行分區。
-- 按行分區
SQL> CREATE TABLE part_andy1
2 (
3 andy_ID NUMBER NOT NULL PRIMARY KEY,
4 FIRST_NAME VARCHAR2(30) NOT NULL,
5 LAST_NAME VARCHAR2(30) NOT NULL,
6 PHONE VARCHAR2(15) NOT NULL,
7 EMAIL VARCHAR2(80),
8 STATUS CHAR(1)
9 )
10 PARTITION BY RANGE (andy_ID)
11 (
12 PARTITION PART1 VALUES LESS THAN (10000) ,
13 PARTITION PART2 VALUES LESS THAN (20000)
14 );
Table created.
-- 按時間分區
SQL> CREATE TABLE part_andy2
2 (
3 ORDER_ID NUMBER(7) NOT NULL,
4 ORDER_DATE DATE,
5 OTAL_AMOUNT NUMBER,
6 CUSTOTMER_ID NUMBER(7),
7 PAID CHAR(1)
8 )
9 PARTITION BY RANGE (ORDER_DATE)
10 (
11 PARTITION p1 VALUES LESS THAN (TO_DATE('2014-10-1', 'yyyy-mm-dd')) ,
12 PARTITION p2 VALUES LESS THAN (TO_DATE('2015-10-1', 'yyyy-mm-dd')) ,
13 PARTITION p3 VALUES LESS THAN (TO_DATE('2016-10-1', 'yyyy-mm-dd')) ,
14 partition p4 values less than (maxvalue)
15 );
Table created.
2. Hash分區
概念:
對於那些無法有效划分范圍的表,可以使用hash分區,這樣對於提高性能還是會有一定的幫助。hash分區會將表中的數據平均分配到你指定的幾個分區中,列所在分區是依據分區列的hash值自動分配,因此你並不能控制也不知道哪條記錄會被放到哪個分區中,hash分區也可以支持多個依賴列。
注意:
hash分區最主要的機制是根據hash算法來計算具體某條紀錄應該插入到哪個分區中,hash算法中最重要的是hash函數,Oracle中如果你要使用hash分區,只需指定分區的數量即可。建議分區的數量采用2的n次方,這樣可以使得各個分區間數據分布更加均勻。
--按hash分區
SQL> create table part_andy3
2 (
3 transaction_id number primary key,
4 item_id number(8) not null
5 )
6 partition by hash(transaction_id)
7 (
8 partition part_01 ,
9 partition part_02 ,
10 partition part_03
11 );
Table created.
3. List分區
概念:
List分區也需要指定列的值,其分區值必須明確指定,該分區列只能有一個,不能像range或者hash分區那樣同時指定多個列做為分區依賴列,但它的單個分區對應值可以是多個。
注意:
在分區時必須確定分區列可能存在的值,一旦插入的列值不在分區范圍內,則插入/更新就會失敗,因此通常建議使用list分區時,要創建一個default分區存儲那些不在指定范圍內的記錄,類似range分區中的maxvalue分區。
-- 按list分區
SQL> create table part_andy4
2 (
3 id varchar2(15 byte) not null,
4 city varchar2(20)
5 )
6 partition by list (city)
7 (
8 partition t_list025 values ('beijing'),
9 partition t_list372 values ('shanghai') ,
10 partition t_list510 values ('changsha'),
11 partition p_other values (default)
12 );
Table created.
4. 組合分區
Oracle10g提供兩種分區組合
– Range-hash
SQL> create table part_andy5
2 (
3 transaction_id number primary key,
4 item_id number(8) not null,
5 item_description varchar2(300),
6 transaction_date date
7 )
8 partition by range(transaction_date)subpartition by hash(transaction_id)
9 (
10 partition part_01 values less than(TO_DATE('2014-10-1', 'yyyy-mm-dd')),
11 partition part_02 values less than(TO_DATE('2015-10-1', 'yyyy-mm-dd')),
12 partition part_03 values less than(maxvalue)
13 );
Table created.
– Range-list
SQL> CREATE TABLE SALES
2 (
3 PRODUCT_ID VARCHAR2(5),
4 SALES_DATE DATE,
5 SALES_COST NUMBER(10),
6 STATUS VARCHAR2(20)
7 )
8 PARTITION BY RANGE(SALES_DATE) SUBPARTITION BY LIST (STATUS)
9 (
10 PARTITION P1 VALUES LESS THAN(TO_DATE('2014-10-1', 'yyyy-mm-dd'))
11 (SUBPARTITION P1SUB1 VALUES ('ACTIVE') ,SUBPARTITION P1SUB2 VALUES ('INACTIVE')
12 ),PARTITION P2 VALUES LESS THAN (TO_DATE('2015-10-1', 'yyyy-mm-dd'))
13 (
14 SUBPARTITION P2SUB1 VALUES ('ACTIVE') ,
15 SUBPARTITION P2SUB2 VALUES ('INACTIVE')
16 )
17 );
Table created.
Oracle11g增加了四種組合
– RANGE-RANGE
– LIST-RANGE
– LIST-HASH
– LIST-LIST
Oracle 11g 中虛擬列來實現。在11g之前 分區表的partition key必須是物理存在的。11g開始提供了虛擬列,並且可以作為partition key 。
--按星期分區
SQL> CREATE TABLE part_andy6
2 (
3 getdate date NOT NULL,
4 wd NUMBER GENERATED ALWAYS AS (TO_NUMBER (TO_CHAR (getdate, 'D'))) VIRTUAL
5 )
6 PARTITION BY LIST (wd)
7 (
8 PARTITION Mon VALUES (1),
9 PARTITION Tue VALUES (2),
10 PARTITION Wed VALUES (3),
11 PARTITION Thu VALUES (4),
12 PARTITION Fri VALUES (5),
13 PARTITION Sat VALUES (6),
14 PARTITION Sun VALUES (7)
15 );
Table created.
SQL>
SQL> insert into part_andy6(getdate) values(sysdate);
1 row created.
SQL> insert into part_andy6(getdate) values(sysdate-1);
1 row created.
SQL> insert into part_andy6(getdate) values(sysdate-2);
1 row created.
SQL> insert into part_andy6(getdate) values(sysdate-3);
1 row created.
SQL> insert into part_andy6(getdate) values(sysdate-4);
1 row created.
SQL> insert into part_andy6(getdate) values(sysdate-5);
1 row created.
SQL> insert into part_andy6(getdate) values(sysdate-6);
1 row created.
SQL> insert into part_andy6(getdate) values(sysdate-7);
1 row created.
-- 檢查測試成功
SQL> select * from part_andy6;
GETDATE WD
------------------- ----------
2014-11-23 16:35:07 1
2014-11-24 16:35:07 2
2014-11-25 16:35:07 3
2014-11-26 16:35:07 4
2014-11-27 16:35:07 5
2014-11-28 16:35:07 6
2014-11-29 16:35:07 7
2014-11-22 16:35:08 7
8 rows selected.
Oracle Database 11g,Interval類型分區表,可以根據加載數據,自動創建指定間隔的分區。
創建按月分區的分區表:
a. 創建分區表
SQL> CREATE TABLE interval_andy7 (a1 NUMBER, a2 DATE)
2 PARTITION BY RANGE (a2)
3 INTERVAL ( NUMTOYMINTERVAL (1, 'MONTH') )
4 (PARTITION part1
5 VALUES LESS THAN (TO_DATE('2014-11-1', 'yyyy-mm-dd')),
6 PARTITION part2
7 VALUES LESS THAN (TO_DATE('2014-12-1', 'yyyy-mm-dd'))
8 );
Table created.
注意:如果在建Interval分區表是沒有把所有的分區寫完成,在插入相關數據后會自動生成分區
b. 查看現在表的分區:
SQL> select table_name,partition_name from user_tab_partitions where table_name='INTERVAL_ANDY7';
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
INTERVALPART PART1
INTERVALPART PART2
c. 插入測試數據:
SQL> begin
2 for i in 0 .. 11 loop
3 insert into interval_andy7 values(i,add_months(to_date('2014-11-1','yyyy-mm-dd'),i));
4 end loop ;
5 commit;
6 end;
7 /
PL/SQL procedure successfully completed.
PL/SQL 過程已成功完成。
補充:add_months()函數獲取前一個月或者下一個月的月份, 參數中 負數 代表 往前, 正數 代表 往后。
--上一個月
select to_char(add_months(trunc(sysdate),-1),'yyyymm') from dual;
--下一個月
select to_char(add_months(trunc(sysdate),1),'yyyymm') from dual;
d. 觀察自動創建的分區:
SQL> select table_name,partition_name from user_tab_partitions where table_name='INTERVAL_ANDY7';
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
INTERVAL_ANDY7 PART1
INTERVAL_ANDY7 PART2
INTERVAL_ANDY7 SYS_P24
INTERVAL_ANDY7 SYS_P25
INTERVAL_ANDY7 SYS_P26
INTERVAL_ANDY7 SYS_P27
INTERVAL_ANDY7 SYS_P28
INTERVAL_ANDY7 SYS_P29
INTERVAL_ANDY7 SYS_P30
INTERVAL_ANDY7 SYS_P31
INTERVAL_ANDY7 SYS_P32
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
INTERVAL_ANDY7 SYS_P33
INTERVAL_ANDY7 SYS_P34
13 rows selected.
下面創建一個以天為間隔的分區表:
1. 創建分區表:
SQL> create table interval_andy8
2 (
3 id number,
4 dt date
5 )
6 partition by range (dt)
7 INTERVAL (NUMTODSINTERVAL(1,'day'))
8 (
9 partition p20141101 values less than (to_date('2014-11-1','yyyy-mm-dd'))
10 );
Table created.
2. 查看表分區:
SQL> select table_name,partition_name from user_tab_partitions where table_name='INTERVAL_ANDY8';
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
INTERVAL_ANDY8 P20141101
3. 插入測試數據:
begin
for i in 1 .. 12 loop
insert into INTERVAL_ANDY8 values(i,trunc(to_date('2014-11-1','yyyy-mm-dd')+i));
end loop;
commit;
end;
/
PL/SQL 過程已成功完成。
4. 觀察自動創建的分區:
SQL> select table_name,partition_name from user_tab_partitions where table_name='INTERVAL_ANDY8';
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
INTERVAL_ANDY8 P20141101
INTERVAL_ANDY8 SYS_P35
INTERVAL_ANDY8 SYS_P36
INTERVAL_ANDY8 SYS_P37
INTERVAL_ANDY8 SYS_P38
INTERVAL_ANDY8 SYS_P39
INTERVAL_ANDY8 SYS_P40
INTERVAL_ANDY8 SYS_P41
INTERVAL_ANDY8 SYS_P42
INTERVAL_ANDY8 SYS_P43
INTERVAL_ANDY8 SYS_P44
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
INTERVAL_ANDY8 SYS_P45
INTERVAL_ANDY8 SYS_P46
13 rows selected.
說明:個人總結+網絡博文
參考: http://blog.csdn.net/tianlesoftware/article/details/5662337