Oracle 管道化表函數

  在PL/SQL中,若是要返回數據的多個行,必須經過返回一個REF CURSOR的遊標,或者一個數據集合(如臨時表或物理表)來完成,而REF CURSOR的侷限於能夠從查詢中選擇的數據,而數據集合的侷限性在於必須先CREATE TABLE(不管是建立臨時表仍是物理表)來進行具體化,具體化後,會由於頻繁刪除表致使大量的碎片。
  Oracle 9i開始,引入了管道化表函數,解決了這種狀況。
  管道化表函數是返回整個行的集合的函數,能夠直接在SQL中進行查詢,他就好像是真正的數據庫表同樣。他存在於內存中,比物理錶速度要快幾十倍。
  管道化表函數必須返回一個集合,在函數中PIPE ROW 語句被用來返回該集合的單個元素,該函數必須以一個空的RETURN語句結束,以代表他已經完成。一旦建立了該函數,就可使用TABLE()操做符從SQL查詢中來調用它。
  使用管道化表函數須要定義如下內容:
  1. 定義一個OBJECT類型的TYPE算法

CREATE TYPE TY_OBJ AS OBJECT ();

  2. 定義一個TYPE繼承了這個TY_OBJ;sql

CREATE TYPE TA_OBJ AS TABLE OF TY_OBJ;

  3. 建立一個管道化函數數據庫

CREATE OR REPLACE FUNCTION FUN_NAME RETURN TA_OBJ PIPELINED IS
BEGIN …… PIPE ROW (); EXCEPTION END;

下面是一個管道化表函數的例子。session

CREATE TYPE TY_NUMLIST AS OBJECT( N1 NUMBER, N2 VARCHAR2(50) ); CREATE TYPE TA_NUMLIST AS TABLE OF TY_NUMLIST; CREATE OR REPLACE FUNCTION FN_NUM RETURN TA_NUMLIST PIPELINED IS FV_NUMLIST TY_NUMLIST; BEGIN
  FOR x IN 1.. 20 LOOP fv_numlist := ty_numlist(x, 'Row'||x); pipe row (fv_numlist); END LOOP; return; END; --接下來能夠查詢結果了;
SELECT * FROM table(fn_num);

  這個管道化函數是能夠帶參數的,好比:建立時,使用了id這個參數app

CREATE FUNCTION MY_FUN(id number) RETURN TT PIPELINED; --那麼查詢時,能夠這樣調用
SELECT * FROM table(mu_fun(11));

下面是一些比較複雜的用法:把一個查詢的結果經過管道化函數來返回。
1. 建立TYPE函數

CREATE OR REPLACE TYPE ty_prov AS object ( prov_id number(8), prov_code varchar2(9), eng_code varchar2(9), prov_name varchar2(12) )

2. 建立TYPEoop

CREATE OR REPLACE TYPE ta_prov AS TABLE OF ty_prov

3.建立管道化函數spa

CREATE OR REPLACE FUNCTION getProvMsg(pp_code varchar2) return ta_prov pipelined IS fv_prov ty_prov; BEGIN
  for x in (SELECT prov_id, prov_code, eng_nm, prov_name FROM bam_t01_province_def WHERE prov_code = pp_code) loop fv_prov := ty_prov(x.prov_id, x.prov_code, x.eng_nm, x.prov_name); pipe row (fv_prov); end loop; return; EXCEPTION when others THEN raise_application_error(-20001,'getProvMsg : '||sqlerrm ); END;

4. 使用下面語句來查詢.net

SQL> select * from table(getProvmsg('100')) ; PROV_ID PROV_CODE ENG_CODE PROV_NAME ---------- --------- --------- ------------
     10100 100       BJ        北京

以上參考自:http://blog.csdn.net/jojo52013145/article/details/6758279code

關於效率的小知識:
  對於物理表,他的數據存儲在物理磁盤上,當數據第一次被READ時,會被load到db cache中,根據LRU算法來決定這些數據會否置換出內存。若是數據一直在內存中,他會被全部session共享,因爲數據是機構化的,因此在內存中掃描的效率是最高的。
  對於臨時表,它和它的索引都是建立在臨時表空間上的,當在一個SESSION中第一次插入數據時,纔開始在用戶的默認臨時表空間下分配臨時數據段,不一樣的SESSION擁有不一樣的段,以保證不一樣會話不會相互影響。臨時表的數據也是結構化的,第一次讀取數據後,數據也會被CACHE到db cache中。
  TABLE()函數是9i的新特性,其實是將一個存儲在內存中的對象結構化後,使這個對象能以表的形式來查詢。對象是以流的方式存儲的,對流的結構化轉換會致使效率降低。因此它的效率應該低於存在於內存中的物理表和臨時表。(但應該高於第一次裝載入內存的物理表和臨時表)

關於對內存的影響:
  網上幾乎沒有資料說起這個TABLE()特性對SGA和PGA形成的嚴重影響。因此咱們暫且忽略吧。或者有高手幫忙補充補充~!

 

from:封燁

相關文章
相關標籤/搜索