簡體   English   中英

批量收集動態SQL

[英]bulk collect dynamic sql

我必須編寫一個動態sql游標,其中有幾種可能會生成選擇查詢的可能性。 因此,我選擇動態方式,並且使用DBMS_SQL包動態創建游標並動態獲取數據。

但是,結果集將是巨大的。 大約11GB(有240萬條記錄,假設每列大約50Byte varchar,select語句的長度約為80列)

因此,我無法立即打開游標。 我想知道是否有一個功能,其中我可以從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;

PL / SQL最佳實踐之一是從游標中以合理大小的塊獲取數據,同時保持游標處於打開狀態。

上面的文檔(請參閱Code 38 )勾畫出一種在運行時才知道選擇列表的方法。 基本上:

  1. 定義適當的類型以將結果提取到其中。 假設所有返回的列的類型均為VARCHAR2

     -- inside DECLARE Ty_FetchResults IS TABLE OF DBMS_SQL.VARCHAR2_TABLE; lvar_results Ty_FetchResults; 
  2. 在每次調用DBMS_SQL.FETCH_ROWS之前, DBMS_SQL.FETCH_ROWS調用DBMS_SQL.DEFINE_ARRAY以啟用批量提取。

  3. 調用DBMS_SQL.FETCH_ROWS以從游標中獲取1000行。
  4. 調用DBMS_SQL.COLUMN_VALUE將獲取的數據復制到結果數組中。
  5. FOR循環中FOR記錄地處理結果。 不必擔心獲取的記錄數:如果有要處理的記錄,則FOR循環將正確運行; 如果結果數組為空,則FOR循環將不會運行。
  6. 當獲取的記錄數小於預期大小時,退出循環。
  7. 記住要使用DBMS_SQL.CLOSEDBMS_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);

另請參見從PL / SQL執行SQL:最佳和最差實踐

限制條款可以解決!

PL / SQL集合本質上是內存中的數組,因此龐大的集合可能會由於其所需的內存量而對系統性能產生不利影響。 在某些情況下,可能有必要將正在處理的數據拆分為多個塊,以使代碼對內存更友好。 可以使用BULK COLLECT語法的LIMIT子句來實現這種“分塊”。

批量收集后,您可以使用限制條款來限制您的RS。 超出限制后,您可以抓住剩余的行。 請參閱此文章http://www.dba-oracle.com/plsql/t_plsql_limit_clause.htm

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM