在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:封燁