關於oracle中的wmsys.wm_concat中的使用問題

這兩天在項目中遇到了一個問題,就是系統中使用了wmsys.wm_concat引發的相關問題,PM也提議不要使用,原因有下:

1.該函數不是oracle公開的系統函數,它的用戶是wmsys,而不是sys或者system,oracle很有可能在版本升級或者補丁的時候取消或者修改這個函數甚至用戶,這種變化oracle是不會公開的。所有可能會由於這個變化而導致異常。

2.大量使用這個函數也會導致臨時表空間爆滿,這是因爲在10.2.0.5中,使用wmsys.wm_concat返回的結果格式是CLOB,CLOB佔用的臨時表空間只有在連接釋放後纔會釋放,部分通過連接池連接數據庫的長連接很有可能導致CLOB佔用臨時表空間不斷累積增大,會導致臨時表空間爆滿的故障

3.如果是在程序中大量使用這個函數的話會引起enq:TT的鎖,可能會導致某些對象被鎖。

解決辦法:

官方文檔給了建議,可以參考該函數自己建立一個函數實現相同的行列轉換功能。


然後我上網找了一些資料,http://www.eygle.com/archives/2012/10/wmsys_wm_concat.html

確實可以實現跟wmsys.wm_concat一樣的功能,下面是這篇文章的實現

create or replace TYPE en_concat_im

   AUTHID CURRENT_USER AS OBJECT
   (
     CURR_STR VARCHAR2(32767),
     STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT en_concat_im) RETURN NUMBER,
     MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT en_concat_im,
       P1 IN VARCHAR2) RETURN NUMBER,
     MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN en_concat_im,
         RETURNVALUE OUT VARCHAR2,
        FLAGS IN NUMBER)
     RETURN NUMBER,
    MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT en_concat_im,
    SCTX2 IN  en_concat_im) RETURN NUMBER
 );
 
create or replace TYPE BODY en_concat_im
   IS
     STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT en_concat_im)
     RETURN NUMBER
     IS
     BEGIN
    SCTX := en_concat_im(NULL) ;
    RETURN ODCICONST.SUCCESS;
   END;
   MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT en_concat_im,
          P1 IN VARCHAR2)
     RETURN NUMBER
    IS
    BEGIN
    IF(CURR_STR IS NOT NULL) THEN
     CURR_STR := CURR_STR || ';' || P1;
    ELSE
      CURR_STR := P1;
    END IF;
    RETURN ODCICONST.SUCCESS;
     END;
    MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN en_concat_im,
         RETURNVALUE OUT VARCHAR2,
         FLAGS IN NUMBER)
   RETURN NUMBER
    IS
     BEGIN
   RETURNVALUE := CURR_STR ;
    RETURN ODCICONST.SUCCESS;
    END;
     MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT en_concat_im,
    SCTX2 IN en_concat_im)
     RETURN NUMBER
     IS
    BEGIN
    IF(SCTX2.CURR_STR IS NOT NULL) THEN
      SELF.CURR_STR := SELF.CURR_STR || ';' || SCTX2.CURR_STR ;
    END IF;
   RETURN ODCICONST.SUCCESS;
   END;
  END;


create or replace FUNCTION en_concat(P1 VARCHAR2) RETURN VARCHAR2 AGGREGATE USING en_concat_im ;

然後運行測試:select en_concat(username) from dba_users;   ok可以實現行列轉換。具體的性能分析可以瀏覽該網址的文章


但是我在運行的時候出了個問題,就是查詢的表數據量比較大的時候會報:Oracle ORA-06502: PL/SQL: 數字或值錯誤 : 字符串緩衝區太小這個錯誤

我當時不明白什麼原因,後面百度了一下這個原因,看到了一篇文章:http://bbs.csdn.net/topics/360059765

樓主的問題:

使用wmsys.wm_concat多列合成一列遇到問題
ORA-22813: 操作數值超出系統的限制

往下看了之後對比了一下這個問題的解決辦法,原理跟上面一樣,也是自定義type來實現,但是有一個不同點的就是,上面的實現我標註的地方,返回的是varchar2類型的

在看看這篇文章裏面的實現:

CREATE OR REPLACE TYPE zh_concat_im
AUTHID CURRENT_USER AS OBJECT
(
  CURR_STR clob,
  STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT zh_concat_im) RETURN NUMBER,
  MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT zh_concat_im,
  P1 IN VARCHAR2) RETURN NUMBER,
  MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN zh_concat_im,
  RETURNVALUE OUT clob,
  FLAGS IN NUMBER)
  RETURN NUMBER,
  MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT zh_concat_im,
  SCTX2 IN zh_concat_im) RETURN NUMBER
);
 
CREATE OR REPLACE TYPE BODY zh_concat_im
IS
  STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT zh_concat_im)
  RETURN NUMBER
  IS
  BEGIN
  SCTX := zh_concat_im(NULL) ;
  RETURN ODCICONST.SUCCESS;
  END;
  MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT zh_concat_im,
 
  P1 IN VARCHAR2)
  RETURN NUMBER
  IS
  BEGIN
  IF(CURR_STR IS NOT NULLTHEN
  CURR_STR := CURR_STR || ',' || P1;
  ELSE
  CURR_STR := P1;
  END IF;
  RETURN ODCICONST.SUCCESS;
  END;
  MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN zh_concat_im,
  RETURNVALUE OUT clob,
  FLAGS IN NUMBER)
  RETURN NUMBER
  IS
  BEGIN
  RETURNVALUE := CURR_STR ;
  RETURN ODCICONST.SUCCESS;
  END;
  MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT zh_concat_im,
  SCTX2 IN zh_concat_im)
  RETURN NUMBER
  IS
  BEGIN
  IF(SCTX2.CURR_STR IS NOT NULLTHEN
  SELF.CURR_STR := SELF.CURR_STR || ',' || SCTX2.CURR_STR ;
  END IF;
  RETURN ODCICONST.SUCCESS;
  END;
END;
 
create or replace FUNCTION zh_concat(P1 VARCHAR2)
RETURN clob AGGREGATE USING zh_concat_im ;

這個定義的的clob類型,所有這個函數可以實現,沒有出現了Oracle ORA-06502:這個錯誤,頓時恍然啊。

至於clob這個類型跟varchar2各位就查資料看看了,但是目前我還是有點不明白,這樣實現也是用clob這個類型,會不會也會臨時表空間增大,目前沒有測試過。

以上就是這兩天查資料看到的這些,有錯的地方希望指出來了;我oracle也不是很熟哈!!!如果哪位大神能更好的說明的那就更好了。


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