ORA-22275: 指定的 LOB 定位器无效
ORA-22275: invalid LOB locator specified
我有一个庞大的 Oracle 函数,用于计算来自 6 个表的数据。
create or replace FUNCTION STATISTICS_FUNCTION(NAMEIN IN VARCHAR2
)
RETURN CLOB
AS
LAST_60_CPU NUMBER;
.............
LINE CLOB;
CURSOR LAST_60_CPU_CURSOR IS
.................
BEGIN
LINE := EMPTY_CLOB();
DBMS_LOB.CREATETEMPORARY(LINE,true);
OPEN LAST_60_CPU_CURSOR;
LOOP
FETCH LAST_60_CPU_CURSOR INTO LAST_60_EVENT_DATE, LAST_60_CPU;
....................
DBMS_LOB.APPEND(LINE, TO_CHAR(LAST_60_EVENT_DATE));
DBMS_LOB.APPEND(LINE, 'I');
DBMS_LOB.APPEND(LINE, TO_CHAR(LAST_60_CPU));
DBMS_LOB.APPEND(LINE, CHR(10));
END LOOP;
CLOSE LAST_60_CPU_CURSOR;
DBMS_LOB.APPEND(LINE, 'LAST_60_CPU');
DBMS_LOB.APPEND(LINE, CHR(10));
.......................................................
-------------------------------------
DBMS_OUTPUT.PUT_LINE(LINE);
RETURN LINE;
END STATISTICS_FUNCTION;
我使用这个 Java 代码来调用函数:
public void callFunction() throws SQLException
{
// initialize the driver and try to make a connection
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "admin", "qwerty");
// prepareCall uses ANSI92 "call" syntax
CallableStatement cstmt = conn.prepareCall("{? = call AGENT_STATISTICS_FUNCTION(?)}");
// get those bind variables and parameters set up
cstmt.registerOutParameter(1, Types.VARCHAR);
cstmt.setString(2, "agent");
// now we can do it, get it, close it, and print it
cstmt.execute();
String result = cstmt.getString(1);
conn.close();
System.out.println(result);
}
我厌倦了在没有这一行的情况下调用该函数:
DBMS_LOB.CREATETEMPORARY(LINE,true);
但是我得到错误:
Connecting to the database local.
ORA-22275: invalid LOB locator specified
ORA-06512: at "SYS.DBMS_LOB", line 639
ORA-06512: at "ADMIN.STATISTICS_FUNCTION", line 596
ORA-06512: at line 7
Process exited.
Disconnecting from the database local.
你知道为什么我在没有 DBMS_LOB.CREATETEMPORARY(LINE,true); 的情况下会出现这个错误吗?
CLOB 类似于文件句柄。因此 Oracle 有时将其称为 lob 定位器。它必须指向 table 的数据段(lob 段)或临时的 tablespace。 LOB 最多可以有 176TB,因此它们不能保存在数据库服务器 RAM 中,也不能保存在 Java JVM 堆中。
有时隐式转换 from/to VARCHAR2 有效,因此看起来 CLOB 和其他变量一样是可变的。你总是应该检查文本超过 32KB 的 CLOB 代码。
PS:您还应该在正确的位置显式调用 freetemporary()。 Java GC 不与数据库引擎对话,因此数据库不知道何时可以释放 TEMP space。
UPDATE1:在处理来自被调用过程的数据后,您应该调用 oracle.sql.CLOB.freetemporary()
或 java.sql.BLOB.free
或 BEGIN DBMS_LOB.CREATETEMPORARY(:CLOB,true); END;
。您还可以在每次调用时重新使用定位器(除非您在连接上使用提交)。我记得我在使用 JDBC API 释放通过 PL/SQL 分配的 LOB 定位器时遇到了一些问题。
更新 2:您可能需要 DBA 权限以及访问数据库服务器才能启动会话跟踪。要启动和停止会话跟踪,请执行:
exec dbms_monitor.session_trace_enable(session_id=>X,serial_num=>Y,binds=>true,waits=>true);
exec dbms_monitor.session_trace_disable(session_id=>X,serial_num=>Y);
其中 X 和 Y 是 v$session 视图中的会话标识符 SID 和 SERIAL#。
这是创建大小为 65KB 的临时 lob 且参数缓存设置为 false
时会话跟踪的样子:
WAIT #0: nam='Disk file operations I/O' ela= 277 FileOperation=2 fileno=201 filetype=2 obj#=-1 tim=1448362135289035
LOBTMPCREATE: c=1000,e=689,p=0,cr=0,cu=2,tim=1448362135289171
WAIT #0: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448362135289218
WAIT #0: nam='SQL*Net message from client' ela= 2594 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448362135291842
WAIT #0: nam='SQL*Net more data from client' ela= 20 driver id=1413697536 #bytes=32 p3=0 obj#=-1 tim=1448362135292339
WAIT #0: nam='SQL*Net more data from client' ela= 796 driver id=1413697536 #bytes=83 p3=0 obj#=-1 tim=1448362135293233
WAIT #0: nam='SQL*Net more data from client' ela= 18 driver id=1413697536 #bytes=65 p3=0 obj#=-1 tim=1448362135293361
WAIT #0: nam='SQL*Net more data from client' ela= 16 driver id=1413697536 #bytes=27 p3=0 obj#=-1 tim=1448362135293449
WAIT #0: nam='SQL*Net more data from client' ela= 749 driver id=1413697536 #bytes=30 p3=0 obj#=-1 tim=1448362135294243
WAIT #0: nam='SQL*Net more data from client' ela= 301 driver id=1413697536 #bytes=12 p3=0 obj#=-1 tim=1448362135294623
WAIT #0: nam='SQL*Net more data from client' ela= 35 driver id=1413697536 #bytes=22 p3=0 obj#=-1 tim=1448362135294786
WAIT #0: nam='SQL*Net more data from client' ela= 16 driver id=1413697536 #bytes=189 p3=0 obj#=-1 tim=1448362135294866
WAIT #0: nam='SQL*Net more data from client' ela= 10 driver id=1413697536 #bytes=103 p3=0 obj#=-1 tim=1448362135294913
WAIT #0: nam='SQL*Net more data from client' ela= 9 driver id=1413697536 #bytes=17 p3=0 obj#=-1 tim=1448362135294955
WAIT #0: nam='SQL*Net more data from client' ela= 697 driver id=1413697536 #bytes=184 p3=0 obj#=-1 tim=1448362135295685
WAIT #0: nam='SQL*Net more data from client' ela= 16 driver id=1413697536 #bytes=98 p3=0 obj#=-1 tim=1448362135295801
WAIT #0: nam='SQL*Net more data from client' ela= 21 driver id=1413697536 #bytes=12 p3=0 obj#=-1 tim=1448362135296189
WAIT #0: nam='SQL*Net more data from client' ela= 12 driver id=1413697536 #bytes=179 p3=0 obj#=-1 tim=1448362135296274
WAIT #0: nam='SQL*Net more data from client' ela= 10 driver id=1413697536 #bytes=93 p3=0 obj#=-1 tim=1448362135296344
WAIT #0: nam='CSS initialization' ela= 7307 p1=0 p2=0 p3=0 obj#=-1 tim=1448362135303779
WAIT #0: nam='CSS operation: action' ela= 2479 function_id=65 p2=0 p3=0 obj#=-1 tim=1448362135306327
WAIT #0: nam='Disk file operations I/O' ela= 823 FileOperation=2 fileno=0 filetype=15 obj#=-1 tim=1448362135307307
WAIT #0: nam='CSS initialization' ela= 22 p1=0 p2=0 p3=0 obj#=-1 tim=1448362135307865
WAIT #0: nam='CSS operation: query' ela= 5 function_id=42 p2=0 p3=0 obj#=-1 tim=1448362135307914
WAIT #0: nam='CSS operation: query' ela= 1 function_id=42 p2=0 p3=0 obj#=-1 tim=1448362135307932
WAIT #0: nam='CSS operation: query' ela= 1 function_id=42 p2=0 p3=0 obj#=-1 tim=1448362135307947
WAIT #0: nam='CSS operation: query' ela= 1 function_id=42 p2=0 p3=0 obj#=-1 tim=1448362135307963
WAIT #0: nam='CSS operation: query' ela= 6 function_id=33 p2=0 p3=0 obj#=-1 tim=1448362135307986
WAIT #0: nam='CSS operation: query' ela= 612 function_id=39 p2=0 p3=0 obj#=-1 tim=1448362135308625
WAIT #0: nam='CSS operation: action' ela= 2589 function_id=65 p2=0 p3=0 obj#=-1 tim=1448362135311258
WAIT #0: nam='direct path write temp' ela= 1373 file number=201 first dba=927747 block cnt=16 obj#=-1 tim=1448362135313337
LOBWRITE: c=9998,e=21487,p=0,cr=0,cu=61,tim=1448362135313441
WAIT #0: nam='SQL*Net message to client' ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448362135313499
WAIT #0: nam='SQL*Net message from client' ela= 3187 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448362135316722
如您所见,它包含写入临时文件的直接路径 tablespace。
这就是使用缓存设置为 true
.
时的样子
WAIT #0: nam='Disk file operations I/O' ela= 267 FileOperation=2 fileno=201 filetype=2 obj#=-1 tim=1448363565002340
LOBTMPCREATE: c=0,e=650,p=0,cr=0,cu=2,tim=1448363565002469
WAIT #0: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448363565002515
WAIT #0: nam='SQL*Net message from client' ela= 2424 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448363565004970
WAIT #0: nam='SQL*Net more data from client' ela= 17 driver id=1413697536 #bytes=32 p3=0 obj#=-1 tim=1448363565005390
WAIT #0: nam='SQL*Net more data from client' ela= 975 driver id=1413697536 #bytes=83 p3=0 obj#=-1 tim=1448363565006434
WAIT #0: nam='SQL*Net more data from client' ela= 21 driver id=1413697536 #bytes=65 p3=0 obj#=-1 tim=1448363565006545
WAIT #0: nam='SQL*Net more data from client' ela= 621 driver id=1413697536 #bytes=27 p3=0 obj#=-1 tim=1448363565007210
WAIT #0: nam='SQL*Net more data from client' ela= 337 driver id=1413697536 #bytes=30 p3=0 obj#=-1 tim=1448363565007648
WAIT #0: nam='SQL*Net more data from client' ela= 20 driver id=1413697536 #bytes=12 p3=0 obj#=-1 tim=1448363565007795
WAIT #0: nam='SQL*Net more data from client' ela= 18 driver id=1413697536 #bytes=22 p3=0 obj#=-1 tim=1448363565007925
WAIT #0: nam='SQL*Net more data from client' ela= 10 driver id=1413697536 #bytes=189 p3=0 obj#=-1 tim=1448363565007983
WAIT #0: nam='SQL*Net more data from client' ela= 555 driver id=1413697536 #bytes=103 p3=0 obj#=-1 tim=1448363565008576
WAIT #0: nam='SQL*Net more data from client' ela= 21 driver id=1413697536 #bytes=17 p3=0 obj#=-1 tim=1448363565008749
WAIT #0: nam='SQL*Net more data from client' ela= 10 driver id=1413697536 #bytes=184 p3=0 obj#=-1 tim=1448363565008811
WAIT #0: nam='SQL*Net more data from client' ela= 176 driver id=1413697536 #bytes=98 p3=0 obj#=-1 tim=1448363565009038
WAIT #0: nam='SQL*Net more data from client' ela= 23 driver id=1413697536 #bytes=12 p3=0 obj#=-1 tim=1448363565009438
WAIT #0: nam='SQL*Net more data from client' ela= 12 driver id=1413697536 #bytes=179 p3=0 obj#=-1 tim=1448363565009525
WAIT #0: nam='SQL*Net more data from client' ela= 12 driver id=1413697536 #bytes=93 p3=0 obj#=-1 tim=1448363565009607
LOBWRITE: c=3000,e=4660,p=0,cr=0,cu=61,tim=1448363565009692
WAIT #0: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448363565009738
WAIT #0: nam='SQL*Net message from client' ela= 3308 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448363565013077
Do you have any idea why I get this error without DBMS_LOB.CREATETEMPORARY(LINE,true);
?
是的。 LOB 是 pointer/reference 到 memory/disk 存储。您需要先 "memalloc()" (...初始化)存储,然后将 pointer/reference 分配给您的 LOB 变量。这就是 dbms_lob.createTemporary()
的用途。除非您使用有效的 LOB 定位器初始化 LOB 变量,否则对该 LOB 变量的所有操作都将失败并返回 ORA-22275: invalid LOB locator specified
.
增强功能:稍微重构一下您的 PL/SQL 函数:
(请注意,我对 last_60_cpu_cursor
游标使用了虚拟查询。不要重复使用游标,使用你自己的!:-))
create or replace
function statistics_function
( namein in varchar2 )
return clob
is
line clob;
cursor last_60_cpu_cursor is
select 1 as last_60_cpu, sysdate as last_60_event_date
from dual
;
begin
dbms_lob.createtemporary(lob_loc => line, cache => true, dur => dbms_lob.call);
for cv in last_60_cpu_cursor loop
dbms_lob.append(line, to_char(cv.last_60_event_date)||'i'||to_char(cv.last_60_cpu)||chr(10));
end loop;
dbms_lob.append(line, 'last_60_cpu'||chr(10));
return line;
end statistics_function;
- 您不需要打开+获取+关闭游标。常规的游标循环就可以了(如果不是更好,这要归功于引擎盖下的隐式批量获取)。
- 明确声明临时 LOB 已缓存(
cache => true
;正如您已经拥有的那样)。这可确保将数据块添加到内存中的 LOB,而不是添加到磁盘上 (cache => false
)。
- 连接要附加到 LOB 的字符串,以尽量减少对
dbms_lob.append()
的调用次数。
- 从您的函数中删除
dbms_output.put_line()
。如果 LOB 内容大于 32K,无论如何都会抛出异常。
此外,在您完成将 LOB 传送回您的 Java 环境后,free the temporary LOB。 (我不是 Java 人,不能自己写 Java 代码片段。)
此外,您的 Java 代码中存在概念错误;将函数的 return 注册为 Types.VARCHAR
是错误的。您应该使用 Oracle's dedicated CLOB type。 (我在 C# 里看到过,Java 一定也有。)
此外,您的解决方案存在一个性能问题。您的函数 return 是一个 LOB。在 PL/SQL 中,每个函数值都作为内部值的深层副本 returned 到其调用者。因此,如果您 return 来自函数的 LOB,则 LOB 内容会在后台使用新的 LOB 定位器 (/pointer/reference) 进行复制。您应该使用 您可以考虑使用存储过程而不是函数,并将 LOB 作为 out nocopy
参数传递给 Java。存储过程将如下所示:
create or replace
procedure statistics_function
( namein in varchar2
, lob_out out nocopy clob )
is
cursor last_60_cpu_cursor is
select 1 as last_60_cpu, sysdate as last_60_event_date
from dual
;
begin
dbms_lob.createtemporary(lob_loc => lob_out, cache => true, dur => dbms_lob.session);
for cv in last_60_cpu_cursor loop
dbms_lob.append(lob_out, to_char(cv.last_60_event_date)||'i'||to_char(cv.last_60_cpu)||chr(10));
end loop;
dbms_lob.append(lob_out, 'last_60_cpu'||chr(10)||chr(10));
end statistics_function;
您的 Java 通话看起来如何,取决于您和 JDBC doc;但是,可以肯定的是,以这种方式编辑 LOB return 意味着不会复制背景内容。当然,释放分配的临时 LOB 的需求仍然适用。
我有一个庞大的 Oracle 函数,用于计算来自 6 个表的数据。
create or replace FUNCTION STATISTICS_FUNCTION(NAMEIN IN VARCHAR2
)
RETURN CLOB
AS
LAST_60_CPU NUMBER;
.............
LINE CLOB;
CURSOR LAST_60_CPU_CURSOR IS
.................
BEGIN
LINE := EMPTY_CLOB();
DBMS_LOB.CREATETEMPORARY(LINE,true);
OPEN LAST_60_CPU_CURSOR;
LOOP
FETCH LAST_60_CPU_CURSOR INTO LAST_60_EVENT_DATE, LAST_60_CPU;
....................
DBMS_LOB.APPEND(LINE, TO_CHAR(LAST_60_EVENT_DATE));
DBMS_LOB.APPEND(LINE, 'I');
DBMS_LOB.APPEND(LINE, TO_CHAR(LAST_60_CPU));
DBMS_LOB.APPEND(LINE, CHR(10));
END LOOP;
CLOSE LAST_60_CPU_CURSOR;
DBMS_LOB.APPEND(LINE, 'LAST_60_CPU');
DBMS_LOB.APPEND(LINE, CHR(10));
.......................................................
-------------------------------------
DBMS_OUTPUT.PUT_LINE(LINE);
RETURN LINE;
END STATISTICS_FUNCTION;
我使用这个 Java 代码来调用函数:
public void callFunction() throws SQLException
{
// initialize the driver and try to make a connection
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "admin", "qwerty");
// prepareCall uses ANSI92 "call" syntax
CallableStatement cstmt = conn.prepareCall("{? = call AGENT_STATISTICS_FUNCTION(?)}");
// get those bind variables and parameters set up
cstmt.registerOutParameter(1, Types.VARCHAR);
cstmt.setString(2, "agent");
// now we can do it, get it, close it, and print it
cstmt.execute();
String result = cstmt.getString(1);
conn.close();
System.out.println(result);
}
我厌倦了在没有这一行的情况下调用该函数:
DBMS_LOB.CREATETEMPORARY(LINE,true);
但是我得到错误:
Connecting to the database local.
ORA-22275: invalid LOB locator specified
ORA-06512: at "SYS.DBMS_LOB", line 639
ORA-06512: at "ADMIN.STATISTICS_FUNCTION", line 596
ORA-06512: at line 7
Process exited.
Disconnecting from the database local.
你知道为什么我在没有 DBMS_LOB.CREATETEMPORARY(LINE,true); 的情况下会出现这个错误吗?
CLOB 类似于文件句柄。因此 Oracle 有时将其称为 lob 定位器。它必须指向 table 的数据段(lob 段)或临时的 tablespace。 LOB 最多可以有 176TB,因此它们不能保存在数据库服务器 RAM 中,也不能保存在 Java JVM 堆中。
有时隐式转换 from/to VARCHAR2 有效,因此看起来 CLOB 和其他变量一样是可变的。你总是应该检查文本超过 32KB 的 CLOB 代码。
PS:您还应该在正确的位置显式调用 freetemporary()。 Java GC 不与数据库引擎对话,因此数据库不知道何时可以释放 TEMP space。
UPDATE1:在处理来自被调用过程的数据后,您应该调用 oracle.sql.CLOB.freetemporary()
或 java.sql.BLOB.free
或 BEGIN DBMS_LOB.CREATETEMPORARY(:CLOB,true); END;
。您还可以在每次调用时重新使用定位器(除非您在连接上使用提交)。我记得我在使用 JDBC API 释放通过 PL/SQL 分配的 LOB 定位器时遇到了一些问题。
更新 2:您可能需要 DBA 权限以及访问数据库服务器才能启动会话跟踪。要启动和停止会话跟踪,请执行:
exec dbms_monitor.session_trace_enable(session_id=>X,serial_num=>Y,binds=>true,waits=>true);
exec dbms_monitor.session_trace_disable(session_id=>X,serial_num=>Y);
其中 X 和 Y 是 v$session 视图中的会话标识符 SID 和 SERIAL#。
这是创建大小为 65KB 的临时 lob 且参数缓存设置为 false
时会话跟踪的样子:
WAIT #0: nam='Disk file operations I/O' ela= 277 FileOperation=2 fileno=201 filetype=2 obj#=-1 tim=1448362135289035
LOBTMPCREATE: c=1000,e=689,p=0,cr=0,cu=2,tim=1448362135289171
WAIT #0: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448362135289218
WAIT #0: nam='SQL*Net message from client' ela= 2594 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448362135291842
WAIT #0: nam='SQL*Net more data from client' ela= 20 driver id=1413697536 #bytes=32 p3=0 obj#=-1 tim=1448362135292339
WAIT #0: nam='SQL*Net more data from client' ela= 796 driver id=1413697536 #bytes=83 p3=0 obj#=-1 tim=1448362135293233
WAIT #0: nam='SQL*Net more data from client' ela= 18 driver id=1413697536 #bytes=65 p3=0 obj#=-1 tim=1448362135293361
WAIT #0: nam='SQL*Net more data from client' ela= 16 driver id=1413697536 #bytes=27 p3=0 obj#=-1 tim=1448362135293449
WAIT #0: nam='SQL*Net more data from client' ela= 749 driver id=1413697536 #bytes=30 p3=0 obj#=-1 tim=1448362135294243
WAIT #0: nam='SQL*Net more data from client' ela= 301 driver id=1413697536 #bytes=12 p3=0 obj#=-1 tim=1448362135294623
WAIT #0: nam='SQL*Net more data from client' ela= 35 driver id=1413697536 #bytes=22 p3=0 obj#=-1 tim=1448362135294786
WAIT #0: nam='SQL*Net more data from client' ela= 16 driver id=1413697536 #bytes=189 p3=0 obj#=-1 tim=1448362135294866
WAIT #0: nam='SQL*Net more data from client' ela= 10 driver id=1413697536 #bytes=103 p3=0 obj#=-1 tim=1448362135294913
WAIT #0: nam='SQL*Net more data from client' ela= 9 driver id=1413697536 #bytes=17 p3=0 obj#=-1 tim=1448362135294955
WAIT #0: nam='SQL*Net more data from client' ela= 697 driver id=1413697536 #bytes=184 p3=0 obj#=-1 tim=1448362135295685
WAIT #0: nam='SQL*Net more data from client' ela= 16 driver id=1413697536 #bytes=98 p3=0 obj#=-1 tim=1448362135295801
WAIT #0: nam='SQL*Net more data from client' ela= 21 driver id=1413697536 #bytes=12 p3=0 obj#=-1 tim=1448362135296189
WAIT #0: nam='SQL*Net more data from client' ela= 12 driver id=1413697536 #bytes=179 p3=0 obj#=-1 tim=1448362135296274
WAIT #0: nam='SQL*Net more data from client' ela= 10 driver id=1413697536 #bytes=93 p3=0 obj#=-1 tim=1448362135296344
WAIT #0: nam='CSS initialization' ela= 7307 p1=0 p2=0 p3=0 obj#=-1 tim=1448362135303779
WAIT #0: nam='CSS operation: action' ela= 2479 function_id=65 p2=0 p3=0 obj#=-1 tim=1448362135306327
WAIT #0: nam='Disk file operations I/O' ela= 823 FileOperation=2 fileno=0 filetype=15 obj#=-1 tim=1448362135307307
WAIT #0: nam='CSS initialization' ela= 22 p1=0 p2=0 p3=0 obj#=-1 tim=1448362135307865
WAIT #0: nam='CSS operation: query' ela= 5 function_id=42 p2=0 p3=0 obj#=-1 tim=1448362135307914
WAIT #0: nam='CSS operation: query' ela= 1 function_id=42 p2=0 p3=0 obj#=-1 tim=1448362135307932
WAIT #0: nam='CSS operation: query' ela= 1 function_id=42 p2=0 p3=0 obj#=-1 tim=1448362135307947
WAIT #0: nam='CSS operation: query' ela= 1 function_id=42 p2=0 p3=0 obj#=-1 tim=1448362135307963
WAIT #0: nam='CSS operation: query' ela= 6 function_id=33 p2=0 p3=0 obj#=-1 tim=1448362135307986
WAIT #0: nam='CSS operation: query' ela= 612 function_id=39 p2=0 p3=0 obj#=-1 tim=1448362135308625
WAIT #0: nam='CSS operation: action' ela= 2589 function_id=65 p2=0 p3=0 obj#=-1 tim=1448362135311258
WAIT #0: nam='direct path write temp' ela= 1373 file number=201 first dba=927747 block cnt=16 obj#=-1 tim=1448362135313337
LOBWRITE: c=9998,e=21487,p=0,cr=0,cu=61,tim=1448362135313441
WAIT #0: nam='SQL*Net message to client' ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448362135313499
WAIT #0: nam='SQL*Net message from client' ela= 3187 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448362135316722
如您所见,它包含写入临时文件的直接路径 tablespace。
这就是使用缓存设置为 true
.
WAIT #0: nam='Disk file operations I/O' ela= 267 FileOperation=2 fileno=201 filetype=2 obj#=-1 tim=1448363565002340
LOBTMPCREATE: c=0,e=650,p=0,cr=0,cu=2,tim=1448363565002469
WAIT #0: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448363565002515
WAIT #0: nam='SQL*Net message from client' ela= 2424 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448363565004970
WAIT #0: nam='SQL*Net more data from client' ela= 17 driver id=1413697536 #bytes=32 p3=0 obj#=-1 tim=1448363565005390
WAIT #0: nam='SQL*Net more data from client' ela= 975 driver id=1413697536 #bytes=83 p3=0 obj#=-1 tim=1448363565006434
WAIT #0: nam='SQL*Net more data from client' ela= 21 driver id=1413697536 #bytes=65 p3=0 obj#=-1 tim=1448363565006545
WAIT #0: nam='SQL*Net more data from client' ela= 621 driver id=1413697536 #bytes=27 p3=0 obj#=-1 tim=1448363565007210
WAIT #0: nam='SQL*Net more data from client' ela= 337 driver id=1413697536 #bytes=30 p3=0 obj#=-1 tim=1448363565007648
WAIT #0: nam='SQL*Net more data from client' ela= 20 driver id=1413697536 #bytes=12 p3=0 obj#=-1 tim=1448363565007795
WAIT #0: nam='SQL*Net more data from client' ela= 18 driver id=1413697536 #bytes=22 p3=0 obj#=-1 tim=1448363565007925
WAIT #0: nam='SQL*Net more data from client' ela= 10 driver id=1413697536 #bytes=189 p3=0 obj#=-1 tim=1448363565007983
WAIT #0: nam='SQL*Net more data from client' ela= 555 driver id=1413697536 #bytes=103 p3=0 obj#=-1 tim=1448363565008576
WAIT #0: nam='SQL*Net more data from client' ela= 21 driver id=1413697536 #bytes=17 p3=0 obj#=-1 tim=1448363565008749
WAIT #0: nam='SQL*Net more data from client' ela= 10 driver id=1413697536 #bytes=184 p3=0 obj#=-1 tim=1448363565008811
WAIT #0: nam='SQL*Net more data from client' ela= 176 driver id=1413697536 #bytes=98 p3=0 obj#=-1 tim=1448363565009038
WAIT #0: nam='SQL*Net more data from client' ela= 23 driver id=1413697536 #bytes=12 p3=0 obj#=-1 tim=1448363565009438
WAIT #0: nam='SQL*Net more data from client' ela= 12 driver id=1413697536 #bytes=179 p3=0 obj#=-1 tim=1448363565009525
WAIT #0: nam='SQL*Net more data from client' ela= 12 driver id=1413697536 #bytes=93 p3=0 obj#=-1 tim=1448363565009607
LOBWRITE: c=3000,e=4660,p=0,cr=0,cu=61,tim=1448363565009692
WAIT #0: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448363565009738
WAIT #0: nam='SQL*Net message from client' ela= 3308 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1448363565013077
Do you have any idea why I get this error without
DBMS_LOB.CREATETEMPORARY(LINE,true);
?
是的。 LOB 是 pointer/reference 到 memory/disk 存储。您需要先 "memalloc()" (...初始化)存储,然后将 pointer/reference 分配给您的 LOB 变量。这就是 dbms_lob.createTemporary()
的用途。除非您使用有效的 LOB 定位器初始化 LOB 变量,否则对该 LOB 变量的所有操作都将失败并返回 ORA-22275: invalid LOB locator specified
.
增强功能:稍微重构一下您的 PL/SQL 函数:
(请注意,我对 last_60_cpu_cursor
游标使用了虚拟查询。不要重复使用游标,使用你自己的!:-))
create or replace
function statistics_function
( namein in varchar2 )
return clob
is
line clob;
cursor last_60_cpu_cursor is
select 1 as last_60_cpu, sysdate as last_60_event_date
from dual
;
begin
dbms_lob.createtemporary(lob_loc => line, cache => true, dur => dbms_lob.call);
for cv in last_60_cpu_cursor loop
dbms_lob.append(line, to_char(cv.last_60_event_date)||'i'||to_char(cv.last_60_cpu)||chr(10));
end loop;
dbms_lob.append(line, 'last_60_cpu'||chr(10));
return line;
end statistics_function;
- 您不需要打开+获取+关闭游标。常规的游标循环就可以了(如果不是更好,这要归功于引擎盖下的隐式批量获取)。
- 明确声明临时 LOB 已缓存(
cache => true
;正如您已经拥有的那样)。这可确保将数据块添加到内存中的 LOB,而不是添加到磁盘上 (cache => false
)。 - 连接要附加到 LOB 的字符串,以尽量减少对
dbms_lob.append()
的调用次数。 - 从您的函数中删除
dbms_output.put_line()
。如果 LOB 内容大于 32K,无论如何都会抛出异常。
此外,在您完成将 LOB 传送回您的 Java 环境后,free the temporary LOB。 (我不是 Java 人,不能自己写 Java 代码片段。)
此外,您的 Java 代码中存在概念错误;将函数的 return 注册为 Types.VARCHAR
是错误的。您应该使用 Oracle's dedicated CLOB type。 (我在 C# 里看到过,Java 一定也有。)
此外,您的解决方案存在一个性能问题。您的函数 return 是一个 LOB。在 PL/SQL 中,每个函数值都作为内部值的深层副本 returned 到其调用者。因此,如果您 return 来自函数的 LOB,则 LOB 内容会在后台使用新的 LOB 定位器 (/pointer/reference) 进行复制。您应该使用 您可以考虑使用存储过程而不是函数,并将 LOB 作为 out nocopy
参数传递给 Java。存储过程将如下所示:
create or replace
procedure statistics_function
( namein in varchar2
, lob_out out nocopy clob )
is
cursor last_60_cpu_cursor is
select 1 as last_60_cpu, sysdate as last_60_event_date
from dual
;
begin
dbms_lob.createtemporary(lob_loc => lob_out, cache => true, dur => dbms_lob.session);
for cv in last_60_cpu_cursor loop
dbms_lob.append(lob_out, to_char(cv.last_60_event_date)||'i'||to_char(cv.last_60_cpu)||chr(10));
end loop;
dbms_lob.append(lob_out, 'last_60_cpu'||chr(10)||chr(10));
end statistics_function;
您的 Java 通话看起来如何,取决于您和 JDBC doc;但是,可以肯定的是,以这种方式编辑 LOB return 意味着不会复制背景内容。当然,释放分配的临时 LOB 的需求仍然适用。