天天看點

Oracle11g新特性:引用分區(reference partitioning)

引用分區(reference partitioning)是Oracle Database 11g Release 1及以上版本的一個新特性。它處理的是父/子對等分區的問題。也就是說,要以某種方式對子表分區,使得各個子表分區分别與一個你表分區存在一對一的關系。在某些情況下這很重要,例如假設有一個資料倉庫,你希望保證一定數量的資料線上(例如最近5年的ORDER資訊),而且要確定相關聯的子表資料(ORDER_LINE_ITEMS資料)也線上。在這個經典的例子中,ORDERS表通常有一個ORDER_DATE列,是以可以很容易地按月分區,這也有利于保證最近5年的資料線上。随着時間推移,隻需加載下一個朋的分區,并删除最老的分區。不過,考慮ORDER_LINE_ITEMS表時會看到存在一個問題。它沒有ORDER_DATE列,而且ORDER_LINE_ITEMS表中根本沒法有可以據以分區的列,是以無法幫助清除老資訊或加載新資訊。

過去,在引用分區出現之前,開發人員必須對資料逆規範化(denormalize),具體做法是:從父表ORDERS将ORDER_DATE屬性複制到子表ORDER_LINE_ITEMS。這會引入備援資料,相應地帶來資料備援存在的一系列常見問題,比如存儲開銷增加、資料加載資源增加、級聯更新問題(如果修改父表,還必須確定更新父表資料的所有副本),等等。另外,如果在資料庫中啟用了外鍵限制(而且确實應當啟用外鍵限制),會發現無法截除或删除父表中原來的分區。例如,下面來建立傳統的ORDERS和ORDER_LINE_ITEMS表。先看ORDERS表:

<code>zx@ORCL&gt;</code><code>create</code> <code>table</code> <code>orders</code>

<code>  </code><code>2  ( </code>

<code>  </code><code>3    </code><code>order</code><code>#      number </code><code>primary</code> <code>key</code><code>,</code>

<code>  </code><code>4    order_date  </code><code>date</code> <code>NOT</code> <code>NULL</code><code>,</code>

<code>  </code><code>5    data       varchar2(30)</code>

<code>  </code><code>6  )</code>

<code>  </code><code>7  enable row movement</code>

<code>  </code><code>8  PARTITION </code><code>BY</code> <code>RANGE (order_date)</code>

<code>  </code><code>9  (</code>

<code> </code><code>10    PARTITION part_2016 </code><code>VALUES</code> <code>LESS THAN (to_date(</code><code>'01-01-2017'</code><code>,</code><code>'dd-mm-yyyy'</code><code>)) ,</code>

<code> </code><code>11    PARTITION part_2017 </code><code>VALUES</code> <code>LESS THAN (to_date(</code><code>'01-01-2018'</code><code>,</code><code>'dd-mm-yyyy'</code><code>)) </code>

<code> </code><code>12  )</code>

<code> </code><code>13  /</code>

<code>Table</code> <code>created.</code>

<code>zx@ORCL&gt;</code><code>insert</code> <code>into</code> <code>orders </code><code>values</code> 

<code>  </code><code>2  ( 1, to_date( </code><code>'01-jun-2016'</code><code>, </code><code>'dd-mon-yyyy'</code> <code>), </code><code>'xxx'</code> <code>);</code>

<code>1 row created.</code>

<code>  </code><code>2  ( 2, to_date( </code><code>'01-jun-2017'</code><code>, </code><code>'dd-mon-yyyy'</code> <code>), </code><code>'xxx'</code> <code>);</code>

<code>zx@ORCL&gt;</code><code>commit</code><code>;</code>

<code>Commit</code> <code>complete.</code>

現在來建立ORDER_LINE_ITEMS表,并插入一些資料指向ORDERS表:

<code>zx@ORCL&gt;</code><code>create</code> <code>table</code> <code>order_line_items</code>

<code>  </code><code>3    </code><code>order</code><code>#      number,</code>

<code>  </code><code>4    line#       number,</code>

<code>  </code><code>5    order_date  </code><code>date</code><code>, </code><code>-- manually copied from ORDERS!</code>

<code>  </code><code>6    data       varchar2(30),</code>

<code>  </code><code>7    </code><code>constraint</code> <code>c1_pk </code><code>primary</code> <code>key</code><code>(</code><code>order</code><code>#,line#),</code>

<code>  </code><code>8    </code><code>constraint</code> <code>c1_fk_p </code><code>foreign</code> <code>key</code><code>(</code><code>order</code><code>#) </code><code>references</code> <code>orders</code>

<code>  </code><code>9  )</code>

<code> </code><code>10  enable row movement</code>

<code> </code><code>11  PARTITION </code><code>BY</code> <code>RANGE (order_date)</code>

<code> </code><code>12  (</code>

<code> </code><code>13    PARTITION part_2016 </code><code>VALUES</code> <code>LESS THAN (to_date(</code><code>'01-01-2017'</code><code>,</code><code>'dd-mm-yyyy'</code><code>)) ,</code>

<code> </code><code>14    PARTITION part_2017 </code><code>VALUES</code> <code>LESS THAN (to_date(</code><code>'01-01-2018'</code><code>,</code><code>'dd-mm-yyyy'</code><code>)) </code>

<code> </code><code>15  )</code>

<code> </code><code>16  /</code>

<code>zx@ORCL&gt;</code><code>insert</code> <code>into</code> <code>order_line_items </code><code>values</code> 

<code>  </code><code>2  ( 1, 1, to_date( </code><code>'01-jun-2016'</code><code>, </code><code>'dd-mon-yyyy'</code> <code>), </code><code>'yyy'</code> <code>);</code>

<code>  </code><code>2  ( 2, 1, to_date( </code><code>'01-jun-2017'</code><code>, </code><code>'dd-mon-yyyy'</code> <code>), </code><code>'yyy'</code> <code>);</code>

現在如果要删除包含2016年資料的ORDER_LINE_ITEMS分區,也可以删除對應2016年的ORDERS分區而不會違反引用完整性限制。盡管我們都很清楚這一點,但資料庫并不知道:

<code>zx@ORCL&gt;</code><code>alter</code> <code>table</code> <code>order_line_items </code><code>drop</code> <code>partition part_2016;</code>

<code>Table</code> <code>altered.</code>

<code>zx@ORCL&gt;</code><code>alter</code> <code>table</code> <code>orders           </code><code>drop</code> <code>partition part_2016;</code>

<code>alter</code> <code>table</code> <code>orders           </code><code>drop</code> <code>partition part_2016</code>

<code>*</code>

<code>ERROR </code><code>at</code> <code>line 1:</code>

<code>ORA-02266: </code><code>unique</code><code>/</code><code>primary</code> <code>keys </code><code>in</code> <code>table</code> <code>referenced </code><code>by</code> <code>enabled </code><code>foreign</code> <code>keys</code>

是以,對資料逆規範化的做活很笨拙,會耗費資源,而且可能破壞資料的完整性。不僅如此,它還會妨礙管理分區表時經常需要做的一項工作:清除老資訊。

下面來看引用分區。采用引用分區,子表會繼承父表的分區機制,而不必對分區鍵逆規範化,而且更重要的是,它會讓資料庫了解這個子表與父表之間存在對等分區特點。也就是說,截除或删除生意人子表分區時,也能删除或截除父表分區。

要重新實作前面的例子,文法很簡單,如下所示,這裡将重用現胡的你表ORDERS,隻需要截除這個表:

<code>zx@ORCL&gt;</code><code>drop</code> <code>table</code> <code>order_line_items </code><code>cascade</code> <code>constraints;</code>

<code>Table</code> <code>dropped.</code>

<code>zx@ORCL&gt;</code><code>truncate</code> <code>table</code> <code>orders;</code>

<code>Table</code> <code>truncated.</code>

建立一個新的子表:

<code>  </code><code>3    </code><code>order</code><code>#      number </code><code>NOT</code> <code>NULL</code><code>,</code>

<code>  </code><code>4    line#       number </code><code>NOT</code> <code>NULL</code><code>,</code>

<code>  </code><code>5    data       varchar2(30),</code>

<code>  </code><code>6    </code><code>constraint</code> <code>c1_pk </code><code>primary</code> <code>key</code><code>(</code><code>order</code><code>#,line#),</code>

<code>  </code><code>7    </code><code>constraint</code> <code>c1_fk_p </code><code>foreign</code> <code>key</code><code>(</code><code>order</code><code>#) </code><code>references</code> <code>orders</code>

<code>  </code><code>8  )</code>

<code>  </code><code>9  enable row movement</code>

<code> </code><code>10  partition </code><code>by</code> <code>reference(c1_fk_p)</code>

<code> </code><code>11  /</code>

<code>  </code><code>2  ( 1, 1, </code><code>'yyy'</code> <code>);</code>

<code>  </code><code>2  ( 2, 1, </code><code>'yyy'</code> <code>);</code>

神奇之處就在CREATE TABLE語句的第10行。在這裡,我們将區間分區語句替換為PARTITION BY REFERENCE。

這允許我們指定要使用的外鍵限制,進而發現分區機制。在這裡可以看到外鍵指向ORDERS表——資料庫讀取ORDERS表的結構,并發現它有兩個分區。是以,子表會有兩個分區。實際上,如果現在查詢資料字典可以得到:

<code>zx@ORCL&gt;</code><code>set</code> <code>linesize 200</code>

<code>zx@ORCL&gt;col </code><code>table</code> <code>for</code> <code>a20</code>

<code>zx@ORCL&gt;col partition_name </code><code>for</code> <code>a20</code>

<code>zx@ORCL&gt;</code><code>select</code> <code>table_name, partition_name</code>

<code>  </code><code>2    </code><code>from</code> <code>user_tab_partitions</code>

<code>  </code><code>3   </code><code>where</code> <code>table_name </code><code>in</code> <code>( </code><code>'ORDERS'</code><code>, </code><code>'ORDER_LINE_ITEMS'</code> <code>)</code>

<code>  </code><code>4   </code><code>order</code> <code>by</code> <code>table_name, partition_name</code>

<code>  </code><code>5  /</code>

<code>TABLE_NAME                                                                                 PARTITION_NAME</code>

<code>------------------------------------------------------------------------------------------ --------------------</code>

<code>ORDERS                                                                                     PART_2016</code>

<code>ORDERS                                                                                     PART_2017</code>

<code>ORDER_LINE_ITEMS                                                                           PART_2016</code>

<code>ORDER_LINE_ITEMS                                                                           PART_2017</code>

可以看到兩個表的結構完全相同。另外,由于資料庫知道這兩個表是相關聯的,可以删除父表分區,并讓它自動清除相關的子表分區(因為子表從父表繼承而來,是以父表分區結構的任何調整都會向下級聯傳遞到子表分區):

<code>zx@ORCL&gt;</code><code>alter</code> <code>table</code> <code>orders </code><code>drop</code> <code>partition part_2016 </code><code>update</code> <code>global</code> <code>indexes;</code>

是以,之前不允許完成的DROP現在則是完全允許的,它會自動級聯傳遞到子表。另外如果使用ADD增加一個分區:

<code>zx@ORCL&gt;</code><code>alter</code> <code>table</code> <code>orders </code><code>add</code> <code>partition</code>

<code>  </code><code>2  part_2018 </code><code>values</code> <code>less than</code>

<code>  </code><code>3  (to_date( </code><code>'01-01-2019'</code><code>, </code><code>'dd-mm-yyyy'</code> <code>));</code>

<code>ORDERS                                                                                     PART_2018</code>

<code>ORDER_LINE_ITEMS                                                                           PART_2018</code>

可以看到,這個操作也會向下級聯傳遞。父表與子表之間存在一種一對一的關系。

參考《ORACLE DATABASE 9I10G11G程式設計藝術》

     本文轉自hbxztc 51CTO部落格,原文連結:http://blog.51cto.com/hbxztc/1893911,如需轉載請自行聯系原作者