Oracle分區表


先說句題外話…   歡迎成都天府軟件園的小伙伴來面基交流經驗~

 

一:什么是分區(Partition)?

分區是將一個表或索引物理地分解為多個更小、更可管理的部分。

分區對應用透明,即對訪問數據庫的應用而言,邏輯上講只有一個表或一個索引(相當於應用“看到”的只是一個表或索引),但在物理上這個表或索引可能由數十個物理分區組成。

每個分區都是一個獨立的對象,可以獨自處理,也可以作為一個更大對象的一部分進行處理。

--------------------------Tips:分表與分區表--------------------------

分表是將一個大表按照一定的規則分解成多張具有獨立存儲空間實體表(子表);

比如一個訂單表 ORDER,采用年月分表后可能就會除 ORDER 本身外還生成許多如 ORDER_201601、ORDER_201602、ORDER_201603… 等的子表。

分表在邏輯上是多張不同的表,而分區表在邏輯上是一張表。

--------------------------------------------------------------------

 

二:什么時候需要分區?

來自官網的兩個建議:

1. Tables greater than 2GB should always be considered for partitioning.(表數據量大於2GB時應該考慮使用分區)

2. Tables containing historical data, in which new data is added into the newest partition. A typical example is a historical table where only the current month's data is updatable and the other 11 months are read only.(新數據均加入至最新分區中的用於存儲歷史數據的表)

 

 

三:分區帶來的好處

1. 提高數據可用性

a) 得益於每個分區的獨立性,優化器會在查詢時有需要的去除未用到的分區(這也叫消除分區)

比如:一個查詢如果只用到了一個表三個分區中的其中一個分區的數據,那么Oracle在執行這個查詢時只會掃描用到的這個分區的數據,不會掃描其他兩個分區的數據。

這在OLAP系統中很有用。

-----------------------延伸閱讀:OLTP與OLAP系統---------------------

OLTP(On-Line Transaction Processing):

聯機事務處理過程,也稱為面向交易的處理過程,其基本特征是前台接收的用戶數據可以立即傳送到計算中心進行處理,並在很短的時間內給出處理結果,實現對用戶操作的快速響應;

這樣的系統事務性要求非常高,一般都是高可用的在線系統,以小的事務以及小的查詢為主。評估其系統的時候,一般看其每秒執行的 Transaction 以及 Execute SQL 的數量。單個數據庫每秒處理的 Transaction 往往超過幾百個或是幾千個,Select 語句的執行量每秒幾千甚至幾萬個;

OLTP是傳統的關系型數據庫的主要應用,典型的OLTP系統有電子商務系統、銀行、證券系統等。

OLAP(On-Line Analytical Processing):

聯機分析處理,是數據倉庫系統的主要應用,所謂數據倉庫是對於大量已經由OLTP形成的數據的一種分析型的數據庫,用於處理商業智能、決策支持等重要的決策信息;

數據倉庫是在數據庫應用到一定程度之后而對歷史數據的加工與分析,讀取較多、更新較少;

OLTP與OLAP簡單對比:

OLAP_OLTP

----------------------------------------------------------------------

b) 分區還可以通過減少停機時間來提高可用性

例如:一個100GB的表,中間的數據如果遭到損壞,那么恢復起來簡直讓人抓狂。

如果這100GB的表被划分為了50個2GB的分區,當其中某個分區數據遭到破壞時,只需要恢復一個2GB的分區數據即可。

出現錯誤時的停機時間將會大大減少,因為恢復所需的工作量大幅減少。

 

2. 方便管理

將一個大的對象分解為數個小對象,操作這些小對象明顯比直接操作原來的大對象更加容易,且占用的資源也更少。

 

3. 改善語句性能(多針對OLAP系統)

a) 並行DML(Parallel DML):

在 Oracle 9i 以前的版本中,PDML(Parallel DML)要求必須分區;

9i 及以后的版本中這個限制已經放松,只有兩個例外:

① 希望在一個表上執行 PDML,而且這個表的一個 LOB列上有一個位圖索引,要並行執行操作就必須對這個表分區;

② 對於並行訪問分區操作,取需要訪問的分區數為並行度

---------------------延伸閱讀:PDML(Parallel DML)---------------------

什么是Parallel(並行)技術?

對於一個大的任務,一般的做法是利用一個進程,串行的執行。

但如果系統資源足夠,可以采用Parallel(並行)技術,把一個大的任務分成若干個小的任務,同時啟用N個進程(或線程),並行的處理這些小的任務,這些並發的進程稱為並行執行服務器(parallel executeion server),它們統一由一個稱為並發協調進程的進程來管理。

注意:

只有在需要處理一個很大的任務(如需要幾個小時的作業),並且要有足夠的系統資源(包括CPU、內存、I/O等)的情況下,才應該考慮使用Parallel技術。

否則,在一個多並發用戶環境下,系統本身資源負擔已經很大,啟用Parallel的話,將會導致某一個會話試圖占用所有的資源,其他會話不得不等待,從而導致系統性能反而下降的情況。

一般情況下,OLTP系統中不要使用Parallel技術,OLAP系統中可以考慮使用。

PDML分類:

  • Parallel Query(並行查詢)
  • Parallel DML(並行DML語句執行)
  • Parallel DDL(並行DDL語句執行)

並行查詢:並行查詢允許將一個select語句划分為多個較小的查詢,每個部分的查詢都並發地運行,然后將各個部分的結果組合起來,提供最終的結果。(多用於全表掃描,索引全掃描等)

並行DML:Parallel DML包括 insert、update、delete、merge,在PDML期間,Oracle可以使用多個並行執行服務器(即並發進程)來執行 insert、update、delete、merge,多個會話同時執行,同時每個會話(並發進程)都有自己的undo段,都是一個獨立的事務,這些事務要么都由並發協調進程提交,要么都rollback。

-----------------------------------------------------------------------

b) 查詢性能:

分區對於不同的系統帶來的影響可能不同;

對OLTP系統而言,需要謹慎使用分區操作,因為在傳統的OLTP系統中,大多數查詢很可能立即返回結果,而且獲取大多數數據可能都通過一個很小的索引區間掃描來完成。故分區帶來的性能方面的優點在 OLTP 系統中可能根本表現不出來。

在一個OLTP系統中,分區如果應用不當,甚至可能使性能下降(分區可能會提高某些類型查詢的性能,但是這些查詢通常不在OLTP系統中使用);

所以有一點你必須明白:分區並不總是和“性能提升”聯系在一起。

對於OLAP系統而言,分區消除與並行查詢將可能帶來效率的大幅提升。

 

 

四:表分區機制

表分區的四種類型:

  • 范圍分區(Range)
  • 散列分區(Hash)
  • 列表分區(List)
  • 組合分區(Range – Hash   或者   Range - List)

1. 范圍分區

范圍(Range)分區將數據基於指定的分區鍵映射到每一個分區中。

這種分區方式最為常用,且常常采用日期作為分區鍵。

注意:

① 每一個分區都需要有一個 VALUES LESS THEN 子句,它指定了該分區的上限值(即該分區能接受的分區鍵的最大值)。記錄里分區鍵的值小於這個上限值時,該記錄會被放入該分區;而當記錄里分區鍵的值等於或大於這個上限值時該記錄會被放入下一個上限值更高的分區中。

② 所有分區里,除了第一個分區,其他分區其實都有一個隱式的下限值(即該分區能接受的分區鍵的最小值),這個下限值就是上一個分區的上限值。

③ 在最后一個分區中,可定義上限值為 MAXVALUE(該值可理解為所有分區中的一個最大上限值,包括空值),當記錄分區鍵的值大於之前所有分區的上限值時,這條記錄會被放入這最后一個分區中。

建表語句示例:

/****************************************************范圍分區示例******************************************/
--創建示例表
create table range_example
(
 id number(2),
 done_date date,
 data varchar2(50)
)

--創建分區,分區鍵為示例表(range_example)中的 done_date 字段
partition by range (done_date)
(
  partition part_1 values less than ( to_date('20160901', 'yyyymmdd') ),
  partition part_2 values less than ( to_date('20161001', 'yyyymmdd') ),
  partition part_3 values less than ( maxvalue )
)

--查看range_example表的分區信息
select * from user_tab_partitions where table_name = 'RANGE_EXAMPLE';

 

分區表創建

查看表分區信息:

分區信息查看

插入數據:

記錄插入

如圖,可以看到示例表 range_example 已經分了三個區。

記錄1的 done_date 為 2016/8/11,小於分區part_1的上限值,則記錄1會被放入part_1分區;

記錄2的 done_date 為 2016/9/8 ,大於分區part_1的上限值但小於part_2的上限值,則記錄2會被放入part_2分區;

記錄3的 done_date 為 2016/10/20,大於前兩個分區的上限值,故會被放入最后一個maxvalue的分區(part_3);

part_2的隱式的下限值實際就是上一個分區part_1的上限值;

 

2. 散列分區

對一個表執行散列分區時,Oracle會對分區鍵應用一個散列(Hash)函數,以此確定數據應當放在 N 個分區中的哪一個分區中。

Oracle建議 N 是 2 的一個冪(如 N = 2、4、8、16 等),從而使表數據得到最佳的總體分布。

當列的值沒有合適的范圍條件時,建議使用散列分區。

注意:

如果改變散列分區的個數 (向一個散列分區表增加或刪除一個分區時),數據會在所有分區中重新分布,即所有數據都會被重寫,因為現在每一行可能屬於一個不同的分區。

為表選擇的散列鍵(分區鍵)應當是惟一的一個列或一組列(該列應有多個不同的值),以便行能在多個分區上均勻地分布。

如果使用散列分區,你將無法控制一行數據最終會放在哪個分區中(由散列函數控制)。

建表語句示例:

/*******************************************散列分區示例***********************************************/
--創建示例表
create table hash_example
(
 id number(2),
 done_date date,
 data varchar2(50)
)

--創建散列分區,分區鍵為示例表(hash_example)中的 done_date 字段
partition by hash (done_date)
(
  partition part_1,
  partition part_2
)

select * from user_tab_partitions where table_name = 'HASH_EXAMPLE';

分區信息:

hash分區信息

 

 

3. 列表分區

列表分區可以根據分區鍵的值明確指定哪些值的數據該放在哪個分區。

注意:

列表分區中如果指定了 default 分區,則分區鍵的值不在任何分區值列表中的記錄,會被放入 default 分區;

而一旦創建了一個 default 分區后,就不能再向這個表中增加更多的分區了;

如果未指定 default 分區,則在插入分區鍵值不在任何分區值列表中的記錄時,Oracle會報錯(ORA-14400: inserted partition key does not map to any partition)。

建表語句示例:

/*******************************************列表分區示例***********************************************/
--創建示例表
create table list_example
(
 id number(2),
 name varchar(30),
 data varchar2(50)
)

--創建列表分區,分區鍵為示例表(list_example)中的 id 字段
partition by list (id)
(
  partition part_1 values ( '1', '3', '5', '7' ),
  partition part_2 values ( '2', '4', '6', '8' ),
  partition part_default values ( default )
)

select * from user_tab_partitions where table_name = 'LIST_EXAMPLE';

分區信息:

列表分區信息

如上,分區鍵(即list_example表中id字段)值為 1、3、5、7 的記錄,會被放入part_1分區;

分區鍵值為 2、4、6、8 的記錄,會被放入part_2分區;

分區鍵值為其他值的記錄,會被放入最后一個part_default分區。

 

4. 組合分區

組合分區是范圍分區與散列分區的組合,或者是范圍分區與列表分區的組合。

在組合分區中,頂層分區機制總是范圍分區,第二級分區機制可能是散列分區也可能是列表分區;

數據物理的存儲在子分區段上,分區(頂層的范圍分區)成為了一個邏輯容器,或者是一個指向實際子分區的容器;

每個頂層分區不需要有相同數目的子分區。

范圍-散列組合分區 建表語句示例:

/******************************************范圍-散列分區**************************************/
create table range_hash_example
(
 id number(2),
 done_date date,
 data varchar2(50)
)

--頂層范圍分區的分區鍵為 range_hash_example 表中的 done_date 字段;
--第二層散列分區的分區鍵為 range_hash_example 表中的 id 字段;
partition by range (done_date) subpartition by hash (id) 
(
  partition part_1 values less than ( to_date('20160901', 'yyyymmdd') )
  (
    subpartition part_1_sub_1,
    subpartition part_1_sub_2
  ),
  
  partition part_2 values less than ( to_date('20161001', 'yyyymmdd') )
  (
    subpartition part_2_sub_1,
    subpartition part_2_sub_2
  ),
  
  partition part_3 values less than ( maxvalue )
  (
    subpartition part_3_sub_1,
    subpartition part_3_sub_2
  )
)

select * from user_tab_partitions where table_name = 'RANGE_HASH_EXAMPLE';

分區信息:

區間-散列分區信息

在如上的范圍-散列組合分區中,Oracle會首先應用范圍(Range)分區規則,得出數據屬於哪個區間,(即先通過 done_date 字段確定記錄是屬於part_1還是part_2還是part_3);

然后再應用散列(Hash)函數,來確定數據最后要放在哪個子分區(物理分區)中,(即通過 id 字段確定記錄是屬於一個分區下的哪個子分區中 )

 

范圍-列表組合分區 建表語句示例:

/******************************************范圍-列表分區**************************************/
create table range_list_example
(
 id number(2),
 done_date date,
 data varchar2(50)
)

--頂層范圍分區的分區鍵為 range_list_example 表中的 done_date 字段;
--第二層列表分區的分區鍵為 range_list_example 表中的 id 字段;
partition by range (done_date) subpartition by list (id) 
(
  partition part_1 values less than ( to_date('20160901', 'yyyymmdd') )
  (
    subpartition part_1_sub_1 values ( '1', '3', '5' ),
    subpartition part_1_sub_2 values ( '2', '4', '6' )
  ),
  
  partition part_2 values less than ( to_date('20161001', 'yyyymmdd') )
  (
    subpartition part_2_sub_1 values ( '11', '13', '15', '17' ),
    subpartition part_2_sub_2 values ( '12', '14' ),
    subpartition part_2_sub_3 values ( '16', '18' )
  ),
  
  partition part_3 values less than ( maxvalue )
  (
    subpartition part_3_sub_1 values ( '21', '23', '25' ),
    subpartition part_3_sub_2 values ( '22', '24', '26' )
  )
)

select * from user_tab_partitions where table_name = 'RANGE_LIST_EXAMPLE';

分區信息:

區間_列表分區信息

如圖,每個頂層的范圍分區可以有不同數目的子分區。

 

5. 小結

一般來講,如果需要將數據按照某個值邏輯聚集,多采用范圍分區。如基於時間數據的按“年”、“月”等分區就是很典型的例子。在許多情況下,范圍分區都能利用到分區消除特性( =  >=  <=  between…and  等篩選條件下)。

如果在表里無法找到一個合適的屬性來按這個屬性完成范圍分區,但你又想享受分區帶來的性能與可用性的提升,則可以考慮使用散列分區。(適合使用 = IN 等篩選條件)

如果數據中有一列或有一組離散值,且按這一列進行分區很有意義,則這樣的數據就很適合采用列表分區。

如果某些數據邏輯上可以進行范圍分區,但是得到的范圍分區還是太大,不能有效管理,則可以考慮使用組合分區。

注意:

分區在最開始創建表時被一同創建,如果后期要更改分區策略的話,需要先重建表。

---------------------------延伸閱讀:自動遞增(自增)分區---------------------------

前面說到基於時間數據的按“年”、“月”進行的典型的范圍分區例子,這里再補充一個應用場景:

假如有一張商品銷售記錄表(products_table),其中簡單記錄着商品的id號,名稱,銷售時間;

當按照銷售時間進行范圍分區時,因為表里的記錄是不斷增加的(每賣出一個商品就會增加一條記錄),這時候就可以考慮創建自增分區;

顧名思義的,當有新記錄插入時,Oracle會根據需要自動增加新分區來存儲新記錄(當新插入的記錄里的分區鍵的值不在任何已有分區范圍內時,Oracle會自動創建一個新的分區)

你可以根據需要來指定自增分區的自動遞增策略,比如按天自增、按周自增、按月自增、按年自增等等(具體自增語句百度一下即可知道);

商品銷售記錄表創建按月自增的范圍分區示例:

create table products_table
(
 id number(2),
 name varchar2(50),
 sale_date date
)
partition by range(sale_date)
  interval (numtoyminterval(1,'month'))
  (
    partition p_month_1 values less than (to_date('2016-01-01','yyyy-mm-dd'))
  )

如圖,取 products_table 中的 sale_date 列作為分區鍵創建按月自增分區;

所有銷售時間在 ‘2016-01-01’之前的記錄都會被放入 p_month_1 分區;

銷售時間在‘2016-01-01’之后的記錄在插入時Oracle會自動創建記錄所屬月的分區;

比如當有銷售時間分別為 2016年1月20日2016年2月20日 的兩條記錄插入時,Oracle會分別創建一個上限值為 ‘2016-01-31’的分區和一個上限值為‘2016-02-29’的分區來存儲這兩條記錄

--------------------------------------------------------------------------------


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM