Oracle-分區表案例

Oracle數據庫開發瞭解分區表
分區就是將一個非常大的表或者索引物理地分解爲多個較小的 可獨立管理的部分.
分區表或索引在邏輯上是一個表或一個索引,但物理上是由多個物理分區組成的.
分區功能通過改善可管理性 性能 可用性,爲各種應用系統帶來了極大的好處.
分區功能的好處:
 1.增強數據可用性:如果表的一個分區因故障或者維護而不能使用時,表的其餘分區仍是可用的;
 2.維護方便:獨立管理多個分區,比維護單個大表要輕鬆;
 3.均衡I/O:可以把不同分區映射到磁盤以平衡I/O,顯著改善性能;
 4.改善查詢性能:對已分區對象的某些查詢可以運行更快,因爲搜索僅限於關心的分區;
 
分區表有哪些??
 Oracle 11g 提供6種表分區方法:範圍分區(range) 散列分區(hash) 列表分區(list) 
 符合分區 間隔分區 引用分區.
 
<範圍分區 partition by range>
 按表中某個列值的範圍進行分區,根據該列的值決定將數據存儲在哪個分區上.
 
創建範圍分區需注意以下幾點:
 1.指明分區方法,分區列,和分區描述
 2.每一個分區都有values less than子句
 3.在最高分區中定義maxvalue,這個maxvalue值高區其他分區中的任何鍵值.
 

例:創建範圍分區

create table range_orders
 (order_id varchar2(10) constraint OR_PK  primary key
 ,order_date date default sysdate
 ,qty integer
 ,payterms varchar2(10)
 ,book_id number(6)
 )
 partition by range (order_date)
 (partition p1 values less than (to_date('20140331','yyyymmdd')) tablespace user01,
  partition p2 values less than (to_date('20140430','yyyymmdd')) tablespace user02,
  partition p3 values less than (to_date('20140531','yyyymmdd')) tablespace user03
 )
 ;
 
SQL> insert into range_orders values ('10001',to_date('20140321','yyyymmdd'),1,'payterm_1',110345);
 1 row inserted
 SQL> insert into range_orders values ('10002',to_date('20140421','yyyymmdd'),1,'payterm_2',110745); 
 1 row inserted
 SQL> insert into range_orders values ('10003',to_date('20140521','yyyymmdd'),1,'payterm_3',110945);
 1 row inserted
 
SQL> commit;
 Commit complete
 
SQL> select rowid,r.* from range_orders r;
 ROWID              ORDER_ID  ORDER_DATE   QTY PAYTERMS  BOOK_ID
 ------------------ ---------- ----------- ---- ---------- -------
 AAADwpAAGAAAACFAAA 10001      2014/3/21     1 payterm_1  110345
 AAADwqAAHAAAACFAAA 10002      2014/4/21     1 payterm_2  110745
 AAADwrAAIAAAACFAAA 10003      2014/5/21     1 payterm_3  110945
可以看到AAG,AAH,AAI 分別代表了三條數據的文件號是6,7,8
備註:這個地方可以看下http://blog.itpub.net/28929558/viewspace-1150766/ 瞭解rowid
驗證下

 SQL> select x.FILE#,x.NAME from v$datafile x;

      FILE# NAME
 ---------- ----------------------------------------
          1 D:\ORACLE\ORADATA\CRISS_DB\SYSTEM01.DBF
          2 D:\ORACLE\ORADATA\CRISS_DB\SYSAUX01.DBF
          3 D:\ORACLE\ORADATA\CRISS_DB\UNDOTBS01.DBF
          4 D:\ORACLE\ORADATA\CRISS_DB\USERS01.DBF
          5 D:\ORACLE\ORADATA\CRISS_DB\TEST01.DBF
          6 D:\ORACLE\ORADATA\CRISS_DB\USER01.DBF
          7 D:\ORACLE\ORADATA\CRISS_DB\USER02.DBF
          8 D:\ORACLE\ORADATA\CRISS_DB\USER03.DBF
  
 8 rows selected
<散列分區 partition by hash>
 散列分區指一個或多個列上應用一個散列函數,數根據該散列值存放在不同的分區中.
 通過散列分區,可以將數據比較均勻地分佈到各個分區中.
 
例:創建散列分區表
SQL> create table hash_orders
	(order_id varchar2(10) constraint HOR_PK  primary key
	,order_date date default sysdate
	,qty integer
	,payterms varchar2(10)
	,book_id number(6)
	)
	partition by hash(order_id)
	( partition hash_p1 tablespace user01
	,partition hash_p2 tablespace user02
	);
  
 Table created
 
SQL> insert into hash_orders select * from range_orders;
  
 3 rows inserted

SQL> select rowid,h.* from hash_orders h;
  
 ROWID              ORDER_ID  ORDER_DATE    QTY PAYTERMS  BOOK_ID
 ------------------ ---------- ----------------- ---------- -------
 AAADyIAAGAAAACNAAA 10002      2014/4/21      1 payterm_2  110745
 AAADyIAAGAAAACNAAB 10003      2014/5/21      1 payterm_3  110945
 AAADyJAAHAAAACNAAA 10001      2014/3/21      1 payterm_1  110345
order_id爲 10002,10003的被存在AAG 6號文件上,第141個塊上的 第1行和第2行
           10001 存放在AAH 7號文件上
 
<列表分區 partition by list>
 當表中某列的值只有幾個的時候,可以採用列表分區,即指定在幾個(根據列值個數)表空間中.
SQL> create table list_orders
	(order_id varchar2(10) constraint LOR_PK  primary key
	,order_date date default sysdate
	,qty integer
	,payterms varchar2(10)
	,book_id number(6)
	)
	partition by list(payterms)
	( partition list_p1 values('payterm_1') tablespace user01
	,partition list_p2 values('payterm_2')tablespace user02
	,partition list_p3 values('payterm_3') tablespace user03
	);
  
 Table created
 
SQL> select rowid,l.* from list_orders l;
  
 ROWID              ORDER_ID  ORDER_DATE     QTY PAYTERMS  BOOK_ID
 ------------------ ---------- ------------------ ---------- -------
 AAADyRAAGAAAACdAAA 10001      2014/3/21       1 payterm_1  110345
 AAADySAAHAAAACdAAA 10002      2014/4/21       1 payterm_2  110745
 AAADyTAAIAAAACVAAA 10003      2014/5/21       1 payterm_3  110945
<複合分區>
 基於範圍分區和列表分區的組合 或 範圍分區和散列分區的組合

SQL> create table comp_orders
	(order_id varchar2(10) constraint COR_PK  primary key
	,order_date date default sysdate
	,qty integer
	,payterms varchar2(10)
	,book_id number(6)
	)
	partition by range (order_date)
	subpartition by list(payterms)
	(partition p1 values less than (to_date('20140331','yyyymmdd'))
			( subpartition p1_sub1 values('payterm_1') tablespace user01
				,subpartition p1_sub2 values('payterm_2') tablespace user02
				,subpartition p1_sub3 values('payterm_3') tablespace user03
				)
	,partition p2 values less than (to_date('20140430','yyyymmdd'))
			( subpartition p2_sub1 values('payterm_1') tablespace user04
				,subpartition p2_sub2 values('payterm_2') tablespace user05
				,subpartition p2_sub3 values('payterm_3') tablespace user06
				)
	,partition p3 values less than (maxvalue) tablespace user07
	)
	;
  
 Table created
 

SQL> select rowid,c.* from comp_orders c;
  
 ROWID              ORDER_ID  ORDER_DATE    QTY PAYTERMS  BOOK_ID
 ------------------ ---------- ----------- ----- ---------- -------
 AAADyZAAGAAAAClAAA 10004      2014/3/21      1 payterm_1  110345
 AAADyZAAGAAAAClAAB 10001      2014/3/21      1 payterm_1  110345
 AAADydAAKAAAACFAAA 10005      2014/4/21      1 payterm_2  110745
 AAADydAAKAAAACFAAB 10002      2014/4/21      1 payterm_2  110745
 AAADyfAAMAAAACFAAA 10006      2014/5/21      1 payterm_3  110945
 AAADyfAAMAAAACFAAB 10003      2014/5/21      1 payterm_3  110945
  
 6 rows selected
PAYTERMS字段值相同,且ORDER_DATE時間區間相同的數據被放到同一個表空間下面.


下面對比下PAYTERMS字段值相同,ORDER_DATE時間區間不同的結果
SQL> insert into comp_orders values('10007',to_date('20140421','yyyymmdd'),1,'payterm_1','113888');
 1 row inserted
  
 SQL> select rowid,c.* from comp_orders c;
  
 ROWID              ORDER_ID  ORDER_DATE   QTY PAYTERMS  BOOK_ID
 ------------------ ---------- ---------------- ---------- -------
 AAADyZAAGAAAAClAAA 10004      2014/3/21     1 payterm_1  110345
 AAADyZAAGAAAAClAAB 10001      2014/3/21     1 payterm_1  110345                                   
 AAADycAAJAAAACFAAA 10007      2014/4/21     1 payterm_1  113888                            
 AAADydAAKAAAACFAAA 10005      2014/4/21     1 payterm_2  110745
 AAADydAAKAAAACFAAB 10002      2014/4/21     1 payterm_2  110745
 AAADyfAAMAAAACFAAA 10006      2014/5/21     1 payterm_3  110945
 AAADyfAAMAAAACFAAB 10003      2014/5/21     1 payterm_3  110945
  
 7 rows selected
ORDER_ID爲10007的數據存放在了另一個表空間內(AAJ AAADyc[AAJ]AAAACFAAA)

<間隔分區>
 間隔分區是oracle 11g release 1 以後版本中新增的特性,它是對範圍分區的擴展,
 可以自動進行等距離範圍的分區.
 
實驗對比一下,間隔分區與範圍分區有什麼區別即可.
 
首先創建一個間隔分區,間隔分區以一個範圍分區爲'起點',並定義一個間隔,
當有數據插入,依據該間隔爲附加的數據創建新的分區.

SQL> create table intvl_orders
	(order_id varchar2(10) constraint INO_PK  primary key
	,order_date date default sysdate
	,qty integer
	,payterms varchar2(10)
	,book_id number(6)
	)
	partition by range (order_date)
	interval(numtoyminterval(1,'MONTH'))
	store in (user01,user02,user03)
	(
	partition p1 values less than (to_date('20140101','yyyymmdd'))
	)
	;
  
 Table created
注意:partition p1 values less than (to_date('20140101','yyyymmdd')) 起始是月初,
不然會報錯 ORA-14767: 無法使用現有上限指定此間隔.至於爲什麼,大家自行去查找下答案吧.
  
 重新創建一個範圍分區表並插入數據!
SQL> drop table range_orders purge;
  
 Table dropped
  
 SQL> 
 SQL> create table range_orders
	(order_id varchar2(10) constraint OR_PK  primary key
	,order_date date default sysdate
	,qty integer
	,payterms varchar2(10)
	,book_id number(6)
	)
	partition by range (order_date)
	(partition p1 values less than (to_date('20140331','yyyymmdd')) tablespace user01,
	partition p2 values less than (to_date('20140430','yyyymmdd')) tablespace user02,
	partition p3 values less than (to_date('20140531','yyyymmdd')) tablespace user03
	)
	;
  
 Table created
  
 SQL> insert into range_orders values ('10003',to_date('20140621','yyyymmdd'),1,'payterm_3',110945);
  
 insert into range_orders values ('10003',to_date('20140621','yyyymmdd'),1,'payterm_3',110945)
  
 ORA-14400: 插入的分區關鍵字未映射到任何分區
  
 SQL> insert into range_orders values ('10003',to_date('20140521','yyyymmdd'),1,'payterm_3',110945);
  
 1 row inserted
可以看到,新創建的範圍分區表最大範圍是20140531,當出入的數據超出分區範圍就會報錯,
需要手工去做分區擴展.下面再給間隔分區插入數據
SQL> insert into intvl_orders values ('10003',to_date('20140621','yyyymmdd'),1,'payterm_3',110945);
  
 1 row inserted
我們插入同樣超出分區範圍的數據,數據插入成功了!
 
我們看一下前後兩次的建表語句有什麼變化
剛剛建好間隔分區表時候oracle內的建表語句:
-- Create table
 create table INTVL_ORDERS
 (
  ORDER_ID  VARCHAR2(10) not null,
  ORDER_DATE DATE default sysdate,
  QTY        INTEGER,
  PAYTERMS  VARCHAR2(10),
  BOOK_ID    NUMBER(6)
 )
 partition by range (ORDER_DATE)
 (
  partition P1 values less than (TO_DATE(' 2014-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
    tablespace USERS
    pctfree 10
    initrans 1
    maxtrans 255
    storage
    (
      initial 64K
      next 1M
      minextents 1
      maxextents unlimited
    )
 );
 -- Create/Recreate primary, unique and foreign key constraints 
 alter table INTVL_ORDERS
  add constraint INO_PK primary key (ORDER_ID)
  using index 
  tablespace USERS
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
插入數據後間隔分區表時候oracle內的建表語句:

-- Create table
 create table INTVL_ORDERS
 (
  ORDER_ID  VARCHAR2(10) not null,
  ORDER_DATE DATE default sysdate,
  QTY        INTEGER,
  PAYTERMS  VARCHAR2(10),
  BOOK_ID    NUMBER(6)
 )
 partition by range (ORDER_DATE)
 (
  partition P1 values less than (TO_DATE(' 2014-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
    tablespace USERS
    pctfree 10
    initrans 1
    maxtrans 255
    storage
    (
      initial 64K
      next 1M
      minextents 1
      maxextents unlimited
    ),
  partition SYS_P22 values less than (TO_DATE(' 2014-07-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
    tablespace USER01
    pctfree 10
    initrans 1
    maxtrans 255
    storage
    (
      initial 64K
      next 1M
      minextents 1
      maxextents unlimited
    )
 );
 -- Create/Recreate primary, unique and foreign key constraints 
 alter table INTVL_ORDERS
  add constraint INO_PK primary key (ORDER_ID)
  using index 
  tablespace USERS
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
結果自動擴展了一個分區!這也就是間隔分區的特點.
間隔分區會根據起始區間和一個間隔(之前我們設置的是一個月),插入數據時,
會創建相應的分區,而不會因數據超出分區範圍導致語句執行失敗.


<引用分區>
 引用分區通過父表繼承分區鍵,可以在邏輯上均分具有分子關係的表.
 分區鍵通過現有的父子關係解析,由現行的主鍵或外鍵約束實施.

SQL> create table range_books
   (bookid number(6) primary key
   ,bookname varchar2(40) not null
   ,booktime date default sysdate
   )
   partition by range(booktime)
   (
   partition p1 values less than (to_date('20140331','yyyymmdd'))
   ,partition p2 values less than (to_date('20140430','yyyymmdd'))
    );
  
 Table created
 

SQL> create table ref_order
   (order_id varchar2(20) constraint RFO_PK primary key
   ,order_date date default sysdate
   ,book_id number(6) not null--not null !!!
   ,constraint RFO_FK foreign key (book_id) references range_books(bookid)
   )
   partition by reference (RFO_FK)
   ;
  
 Table created
上面的實驗,通過使用外鍵發現分區機制,外鍵[RFO_FK]指向父表'range_books',
因此,子表'ref_order'就按照父表的分區方式進行相應的分區.


注意:創建引用分區表時,通過[partition by reference]子句指定分區方法,
其後括號中指定分區使用的約束.外鍵約束引用的列必須具有not null約束.
=========================================================================
 分區表維護:
主要的就是 刪除分區 | 增加分區 | 合併分區 | 移動分區 | 重命名 | 截斷分區
刪除分區: 
	alter table range_orders drop partition p2;
	
增加分區: 
	alter table range_orders add partition p2 values 
	less than (to_date('20140430','yyyymmdd')) tablespace user02;
	
合併分區: 
	alter table range_orders merge partition p1,p2 into partition p2;
 
移動分區: 
	alter table range_orders move partition p2 tablespace user05;
 
重命名: 
	alter table range_orders rename partition p2 to p1;
 
截斷分區: 
	alter table range_orders truncate partition p1;


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章