一次PLSQL處理LOB欄位的優化
前面一篇文章介紹了利用LOB來避免字串超長的問題。在編寫過程中,碰到了LOB處理效率比較低的問題,這裡簡單介紹了一下優化LOB處理的過程。
字串連線超長的解決(二):http://yangtingkun.itpub.net/post/468/482122
問題源自上面給出的連結。為了實現字串的聚集合並,因此用LOB來避免字串長度超過VARCHAR2型別長度的限制。
第一次PL/SQL程式碼的實現為:
SQL> CREATE OR REPLACE TYPE T_LINK_LOB AS OBJECT (
2 V_LOB CLOB,
3 STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT T_LINK_LOB) RETURN NUMBER,
4 MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT T_LINK_LOB, VALUE IN VARCHAR2) RETURN NUMBER,
5 MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN T_LINK_LOB, RETURNVALUE OUT CLOB, FLAGS IN NUMBER) RETURN NUMBER,
6 MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT T_LINK_LOB, CTX2 IN T_LINK_LOB) RETURN NUMBER
7 )
8 /
型別已建立。
SQL> CREATE OR REPLACE TYPE BODY T_LINK_LOB IS
2 STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT T_LINK_LOB) RETURN NUMBER IS
3 BEGIN
4 SCTX := T_LINK_LOB(NULL);
5 DBMS_LOB.CREATETEMPORARY(SCTX.V_LOB, TRUE, DBMS_LOB.SESSION);
6 DBMS_LOB.OPEN(SCTX.V_LOB, DBMS_LOB.LOB_READWRITE);
7 RETURN ODCICONST.SUCCESS;
8 END;
9
10 MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT T_LINK_LOB, VALUE IN VARCHAR2) RETURN NUMBER IS
11 BEGIN
12 DBMS_LOB.WRITEAPPEND(SELF.V_LOB, LENGTH(VALUE) + 1, VALUE || ',');
13 RETURN ODCICONST.SUCCESS;
14 END;
15
16 MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN T_LINK_LOB, RETURNVALUE OUT CLOB, FLAGS IN NUMBER) RETURN NUMBER IS
17 BEGIN
18 DBMS_LOB.CREATETEMPORARY(RETURNVALUE, TRUE, DBMS_LOB.CALL);
19 DBMS_LOB.APPEND(RETURNVALUE, SELF.V_LOB);
20 DBMS_LOB.TRIM(RETURNVALUE, DBMS_LOB.GETLENGTH(RETURNVALUE) - 1);
21 RETURN ODCICONST.SUCCESS;
22 END;
23
24 MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT T_LINK_LOB, CTX2 IN T_LINK_LOB) RETURN NUMBER IS
25 BEGIN
26 NULL;
27 RETURN ODCICONST.SUCCESS;
28 END;
29 END;
30 /
型別主體已建立。
SQL> CREATE OR REPLACE FUNCTION F_LINK_LOB(P_STR VARCHAR2) RETURN CLOB
2 AGGREGATE USING T_LINK_LOB;
3 /
函式已建立。
這時呼叫這個聚集函式的效率比較低:
SQL> SET TIMING ON
SQL> SET AUTOT TRACE STAT
SQL> SELECT F_LINK_LOB(SYNONYM_NAME) FROM ALL_SYNONYMS WHERE ROWNUM <= 10000;
已用時間: 00: 00: 39.67
Statistics
----------------------------------------------------------
153 recursive calls
3125947 db block gets
211709 consistent gets
43 physical reads
0 redo size
1990553 bytes sent via SQL*Net to client
1166302 bytes received via SQL*Net from client
6443 SQL*Net roundtrips to/from client
9 sorts (memory)
0 sorts (disk)
1 rows processed
檢查了一下DBMS_LOB包,發現用COPY命令可以替換APPEND和TRIM過程,這樣可以減少一次LOB物件的讀寫:
SQL> CONN TEST/TEST
已連線。
SQL> SET TIMING OFF
SQL> CREATE OR REPLACE TYPE BODY T_LINK_LOB IS
2 STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT T_LINK_LOB) RETURN NUMBER IS
3 BEGIN
4 SCTX := T_LINK_LOB(NULL);
5 DBMS_LOB.CREATETEMPORARY(SCTX.V_LOB, TRUE, DBMS_LOB.SESSION);
6 DBMS_LOB.OPEN(SCTX.V_LOB, DBMS_LOB.LOB_READWRITE);
7 RETURN ODCICONST.SUCCESS;
8 END;
9
10 MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT T_LINK_LOB, VALUE IN VARCHAR2) RETURN NUMBER IS
11 BEGIN
12 DBMS_LOB.WRITEAPPEND(SELF.V_LOB, LENGTH(VALUE) + 1, VALUE || ',');
13 RETURN ODCICONST.SUCCESS;
14 END;
15
16 MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN T_LINK_LOB, RETURNVALUE OUT CLOB, FLAGS IN NUMBER) RETURN NUMBER IS
17 BEGIN
18 DBMS_LOB.CREATETEMPORARY(RETURNVALUE, TRUE, DBMS_LOB.CALL);
19 DBMS_LOB.COPY(RETURNVALUE, SELF.V_LOB, DBMS_LOB.GETLENGTH(SELF.V_LOB) - 1);
20 RETURN ODCICONST.SUCCESS;
21 END;
22
23 MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT T_LINK_LOB, CTX2 IN T_LINK_LOB) RETURN NUMBER IS
24 BEGIN
25 NULL;
26 RETURN ODCICONST.SUCCESS;
27 END;
28 END;
29 /
型別主體已建立。
SQL> CREATE OR REPLACE FUNCTION F_LINK_LOB(P_STR VARCHAR2) RETURN CLOB
2 AGGREGATE USING T_LINK_LOB;
3 /
函式已建立。
SQL> SET TIMING ON
SQL> SET AUTOT TRACE STAT
SQL> SELECT F_LINK_LOB(SYNONYM_NAME) FROM ALL_SYNONYMS WHERE ROWNUM <= 10000;
已用時間: 00: 00: 39.46
Statistics
----------------------------------------------------------
7 recursive calls
3125933 db block gets
211660 consistent gets
0 physical reads
0 redo size
1990553 bytes sent via SQL*Net to client
1166302 bytes received via SQL*Net from client
6443 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
雖然邏輯讀和執行時間都有所減少,但是與總執行時間相比優化效果可以忽略,再次觀察PL/SQL,發現預設情況下沒有使用NOCOPY方式處理輸出引數,再次修改程式:
SQL> CONN TEST/TEST
已連線。
SQL> SET TIMING OFF
SQL> CREATE OR REPLACE TYPE T_LINK_LOB AS OBJECT (
2 V_LOB CLOB,
3 STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT NOCOPY T_LINK_LOB) RETURN NUMBER,
4 MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT NOCOPY T_LINK_LOB, VALUE IN VARCHAR2) RETURN NUMBER,
5 MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN T_LINK_LOB, RETURNVALUE OUT NOCOPY CLOB, FLAGS IN NUMBER) RETURN NUMBER,
6 MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT NOCOPY T_LINK_LOB, CTX2 IN T_LINK_LOB) RETURN NUMBER
7 )
8 /
型別已建立。
SQL> CREATE OR REPLACE TYPE BODY T_LINK_LOB IS
2 STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT NOCOPY T_LINK_LOB) RETURN NUMBER IS
3 BEGIN
4 SCTX := T_LINK_LOB(NULL);
5 DBMS_LOB.CREATETEMPORARY(SCTX.V_LOB, TRUE, DBMS_LOB.SESSION);
6 DBMS_LOB.OPEN(SCTX.V_LOB, DBMS_LOB.LOB_READWRITE);
7 RETURN ODCICONST.SUCCESS;
8 END;
9
10 MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT NOCOPY T_LINK_LOB, VALUE IN VARCHAR2) RETURN NUMBER IS
11 BEGIN
12 DBMS_LOB.WRITEAPPEND(SELF.V_LOB, LENGTH(VALUE) + 1, VALUE || ',');
13 RETURN ODCICONST.SUCCESS;
14 END;
15
16 MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN T_LINK_LOB, RETURNVALUE OUT NOCOPY CLOB, FLAGS IN NUMBER) RETURN NUMBER IS
17 BEGIN
18 DBMS_LOB.CREATETEMPORARY(RETURNVALUE, TRUE, DBMS_LOB.CALL);
19 DBMS_LOB.COPY(RETURNVALUE, SELF.V_LOB, DBMS_LOB.GETLENGTH(SELF.V_LOB) - 1);
20 RETURN ODCICONST.SUCCESS;
21 END;
22
23 MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT NOCOPY T_LINK_LOB, CTX2 IN T_LINK_LOB) RETURN NUMBER IS
24 BEGIN
25 NULL;
26 RETURN ODCICONST.SUCCESS;
27 END;
28 END;
29 /
型別主體已建立。
SQL> CREATE OR REPLACE FUNCTION F_LINK_LOB(P_STR VARCHAR2) RETURN CLOB
2 AGGREGATE USING T_LINK_LOB;
3 /
函式已建立。
SQL> SET TIMING ON
SQL> SET AUTOT TRACE STAT
SQL> SELECT F_LINK_LOB(SYNONYM_NAME) FROM ALL_SYNONYMS WHERE ROWNUM <= 10000;
已用時間: 00: 00: 35.14
Statistics
----------------------------------------------------------
7 recursive calls
3125933 db block gets
211720 consistent gets
0 physical reads
0 redo size
1990553 bytes sent via SQL*Net to client
1166302 bytes received via SQL*Net from client
6443 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
新增了NOCOPY後,執行時間提高了1/8。可以看到對於LOB欄位的處理方式對效能的影響還是很大的,如果在建立臨時LOB物件的時候不指定CACHE選項,可以看到執行時間要比CACHE的速度慢一倍以上:
SQL> CREATE OR REPLACE TYPE BODY T_LINK_LOB IS
2 STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT NOCOPY T_LINK_LOB) RETURN NUMBER IS
3 BEGIN
4 SCTX := T_LINK_LOB(NULL);
5 DBMS_LOB.CREATETEMPORARY(SCTX.V_LOB, FALSE, DBMS_LOB.CALL);
6 DBMS_LOB.OPEN(SCTX.V_LOB, DBMS_LOB.LOB_READWRITE);
7 RETURN ODCICONST.SUCCESS;
8 END;
9
10 MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT NOCOPY T_LINK_LOB, VALUE IN VARCHAR2) RETURN NUMBER IS
11 BEGIN
12 DBMS_LOB.WRITEAPPEND(SELF.V_LOB, LENGTH(VALUE) + 1, VALUE || ',');
13 RETURN ODCICONST.SUCCESS;
14 END;
15
16 MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN T_LINK_LOB, RETURNVALUE OUT NOCOPY CLOB, FLAGS IN NUMBER) RETURN NUMBER IS
17 BEGIN
18 DBMS_LOB.CREATETEMPORARY(RETURNVALUE, FALSE, DBMS_LOB.SESSION);
19 DBMS_LOB.COPY(RETURNVALUE, SELF.V_LOB, DBMS_LOB.GETLENGTH(SELF.V_LOB) - 1);
20 RETURN ODCICONST.SUCCESS;
21 END;
22
23 MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT NOCOPY T_LINK_LOB, CTX2 IN T_LINK_LOB) RETURN NUMBER IS
24 BEGIN
25 NULL;
26 RETURN ODCICONST.SUCCESS;
27 END;
28 END;
29 /
型別主體已建立。
已用時間: 00: 00: 00.07
SQL> CONN TEST/TEST
已連線。
SQL> SET AUTOT TRACE STAT
SQL> SELECT F_LINK_LOB(SYNONYM_NAME) FROM ALL_SYNONYMS WHERE ROWNUM <= 10000;
已用時間: 00: 01: 33.90
Statistics
----------------------------------------------------------
6 recursive calls
2960983 db block gets
211636 consistent gets
181384 physical reads
0 redo size
1990553 bytes sent via SQL*Net to client
1166302 bytes received via SQL*Net from client
6443 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-588757/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- lob欄位的ora-1555處理方案
- 可以處理LOB欄位的常用字元函式字元函式
- oracle中lob欄位Oracle
- LOB欄位EMPTY_LOB和NULL的區別Null
- 【LOB】使用資料泵時 LOB 欄位存放位置
- ORACLE LOB大欄位維護Oracle
- 帶有LOB欄位的表遷移
- JDBC處理包含CLOB欄位JDBC
- BLOB及CLOB欄位處理
- LOB欄位資料清理 - 更新為null後move lobNull
- Oracle 帶LOB欄位的表的遷移Oracle
- lob欄位表空間遷移
- 釋放大資料量的lob欄位空間大資料
- PL/SQL 插入clob欄位處理SQL
- Oracle 建表時LOB欄位語法Oracle
- sql 統計多個欄位的和(如果欄位中含有 null 的處理)SQLNull
- 資料處理之欄位合併
- 利用PLSQL包載入CLOB欄位SQL
- 小議lob欄位結構和儲存
- MySQL和Oracle的新增欄位的處理差別MySqlOracle
- plsql異常處理SQL
- 《轉》ORACLE LOB 大物件處理Oracle物件
- Oracle中Blob欄位的寫入處理(一) (轉)Oracle
- Oracle LOB資料型別的處理Oracle資料型別
- 【開發篇plsql】plsql事務處理SQL
- Oracle lob載入bfile資料到blob欄位中Oracle
- 如何處理sql server中的image型別的欄位?SQLServer型別
- 如果新增欄位是外來鍵,如何處理?
- springboot~mybatis統一處理公有欄位Spring BootMyBatis
- innodb引擎對自增欄位(auto_increment)的處理REM
- 欄位處理rtrim去掉結尾的特殊字元和空格字元
- Go 中時間型別欄位的 JSON 序列化和反序列化的處理技巧Go型別JSON
- Mysql多欄位大表的幾種優化方法MySql優化
- 使用plsql 匯出欄位為json 格式SQLJSON
- 多型關聯自定義的型別欄位的處理多型型別
- DatabaseLink不支援merge和lob欄位查詢Database
- lob欄位型別轉換ora-22858型別
- exp,imp 不同表空間大欄位處理方法