我必须编写一个动态sql游标,其中有几种可能性来生成select查询。因此,我正在选择动态,我正在使用DBMS_SQL包动态创建游标并动态获取数据。
然而,结果集将是巨大的。大约11GB(有240万条记录,选择语句大约80条长,每列约50Byte varchar)
因此我无法立刻打开光标。我想知道是否有一个功能,我可以从curosr获取数据保持curosr打开时间为1000条记录的块(我将不得不动态地执行此操作)
请找到附加的代码,它只提取并打印列的值(一个示例案例)我想在这里使用bul collect \
由于
---------------code sample--------------------------------------
--create or replace type TY_DIMDEAL AS TABLE OF VARCHAR2(50) ;
create or replace procedure TEST_PROC (po_recordset out sys_refcursor)
as
v_col_cnt INTEGER;
v_ind NUMBER;
rec_tab DBMS_SQL.desc_tab;
v_cursor NUMBER;
lvar_output number:=0;
lvar_output1 varchar2(100);
lvar_output3 varchar2(100);
lvar_output2 varchar2(100);
LVAR_TY_DIMDEAL TY_DIMDEAL;
lvarcol varchar2(100);
begin
--
LVAR_TY_DIMDEAL := TY_DIMDEAL();
lvar_output1 := '';
v_cursor := dbms_sql.open_cursor;
dbms_sql.parse(v_cursor, 'select to_char(Field1) , to_char(fiel2) , to_char(field3) from table,table2 ', dbms_sql.native);
dbms_sql.describe_columns(v_cursor, v_col_cnt, rec_tab);
FOR v_pos in 1..rec_tab.LAST LOOP
LVAR_TY_DIMDEAL.EXTEND();
DBMS_SQL.define_column( v_cursor, v_pos ,LVAR_TY_DIMDEAL(v_pos),20);
END LOOP;
-- DBMS_SQL.define_column( v_cursor, 1 ,lvar_output1,20);
--DBMS_SQL.define_column( v_cursor, 2 ,lvar_output2,20);
--DBMS_SQL.define_column( v_cursor, 3 ,lvar_output3,20);
v_ind := dbms_sql.execute( v_cursor );
LOOP
v_ind := DBMS_SQL.FETCH_ROWS( v_cursor );
EXIT WHEN v_ind = 0;
lvar_output := lvar_output+1;
dbms_output.put_line ('row number '||lvar_output) ;
FOR v_col_seq IN 1 .. rec_tab.COUNT LOOP
LVAR_TY_DIMDEAL(v_col_seq):= '';
DBMS_SQL.COLUMN_VALUE( v_cursor, v_col_seq,LVAR_TY_DIMDEAL(v_col_seq));
dbms_output.put_line (LVAR_TY_DIMDEAL(v_col_seq));
END LOOP;
END LOOP;
end TEST_PROC;
答案 0 :(得分:3)
在保持光标打开的同时从光标中获取合理大小的块中的数据是PL/SQL Best Practices之一。
上面的文档(参见Code 38
item)草拟了一种方法,用于何时在运行时才知道选择列表。基本上是:
定义适当的类型以将结果提取到。假设所有返回的列都是VARCHAR2
的类型:
-- inside DECLARE
Ty_FetchResults IS TABLE OF DBMS_SQL.VARCHAR2_TABLE;
lvar_results Ty_FetchResults;
在每次致电DBMS_SQL.FETCH_ROWS
之前,请致电DBMS_SQL.DEFINE_ARRAY
以启用批量抓取。
DBMS_SQL.FETCH_ROWS
从光标中获取1000行。DBMS_SQL.COLUMN_VALUE
将获取的数据复制到结果数组中。FOR
循环中处理结果,逐个记录。不要担心获取记录的数量:如果有要处理的记录,FOR
循环将正确运行;如果结果数组为空,则FOR
循环将不会运行。DBMS_SQL.CLOSE
光标。你的循环体看起来像这样:
LOOP
FOR j IN 1..v_col_cnt LOOP
DBMS_SQL.DEFINE_ARRAY(v_cursor, j, lvar_results(j), 1000, 1);
END LOOP;
v_ind := DBMS_SQL.FETCH_ROWS(v_cursor);
FOR j IN 1..v_col_cnt LOOP
lvar_results(j).DELETE;
DBMS_SQL.COLUMN_VALUE(v_cursor, j, lvar_results(j));
END LOOP;
-- process the results, record by record
FOR i IN 1..lvar_results(1).COUNT LOOP
-- process a single record...
-- your logic goes here
END LOOP;
EXIT WHEN lvar_results(1).COUNT < 1000;
END LOOP;
-- don't forget: DBMS_CLOSE(v_cursor);
答案 1 :(得分:0)
限制条款可以救援!
PL / SQL集合本质上是内存中的数组,非常庞大 集合可能会对系统性能产生不利影响 他们需要的内存量。在某些情况下,它可能是 必须将正在处理的数据拆分成块来制作 代码更加内存友好。这种“分块”可以用来实现 BULK COLLECT语法的LIMIT子句。
您可以在批量收集条款后限制您的RS使用限制条款。 在您超出限制之后,您可以获得剩余的行数。 看这篇文章 http://www.dba-oracle.com/plsql/t_plsql_limit_clause.htm