2013-08-06 3 views
2

Je dois écrire un curseur SQL dynamique où il y a plusieurs possibilités dans lesquelles la requête select sera générée. Par conséquent je choisis la dynamique et j'emploie le paquet de DBMS_SQL pour créer dynamiquement un curseur et rechercher dynamiquement les données.vrac collecter dynamique SQL

Cependant, le jeu de résultats va être énorme. environ 11 Go (il y a 2,4 millions d'enregistrements et l'instruction select sera d'environ 80 cols en supposant environ 50Byte varchar par colonne)

Par conséquent, je ne peux pas ouvrir le curseur immédiatement. Je veux savoir s'il y a une caractéristique dans laquelle je peux aller chercher les données du curosr en gardant le curosr ouvert pour des blocs de 1000 disques à la fois (je vais devoir le faire dynamiquement)

Veuillez trouver le code ci-joint va chercher et imprime la valeur des colonnes (un exemple de cas) Je veux utiliser bul recueillir ici \

Merci

---------------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; 
+1

Le titre mentionne déjà 'bulk collect'; est-ce que vous manquez juste la clause ['limit'] (http://docs.oracle.com/cd/E18283_01/appdev.112/e17126/tuning.htm#sthref1006) pour rendre les lots plus petits? Il y a un article à ce sujet [ici] (http://www.oracle.com/technetwork/issue-archive/2008/08-mar/o28plsql-095155.html). –

+0

@AlexPoole Comment appliquer 'bulk collect' au curseur construit avec' DBMS_SQL' et le nombre dynamique de colonnes? – ThinkJet

+0

@ThinkJet - Je crois que vous pouvez utiliser [définitions de colonne en vrac] (http://docs.oracle.com/cd/E11882_01/appdev.112/e25788/d_sql.htm#ARPLS68248), mais je n'ai pas d'exemple à la main. Il peut être plus simple d'utiliser 'execute immediate' et de convertir un curseur ref pour obtenir les métadonnées si nécessaire. Je suppose que "limite" impliquerait cela, ce que je n'avais pas vraiment l'intention de faire ... –

Répondre

3

Récupération des données à partir d'un curseur dans des blocs de taille raisonnable, tout en gardant le curseur ouvert, est l'un des PL/SQL Best Practices.

Le document ci-dessus (voir Code 38 item) esquisse une approche lorsque la liste de sélection n'est pas connue avant l'exécution. Fondamentalement:

  1. Définissez un type approprié pour récupérer les résultats dans. Supposons que toutes les colonnes retournées seront par le type de VARCHAR2:

    -- inside DECLARE 
    Ty_FetchResults IS TABLE OF DBMS_SQL.VARCHAR2_TABLE; 
    lvar_results Ty_FetchResults; 
    
  2. Avant chaque appel à DBMS_SQL.FETCH_ROWS, appelez DBMS_SQL.DEFINE_ARRAY pour activer le chargement par lots.

  3. Appelez DBMS_SQL.FETCH_ROWS pour extraire 1000 lignes du curseur.
  4. Appelez DBMS_SQL.COLUMN_VALUE pour copier les données récupérées dans votre tableau de résultats.
  5. Traite les résultats, enregistrement par enregistrement, dans une boucle FOR. Ne vous inquiétez pas du nombre d'enregistrements récupérés: s'il y a des enregistrements à traiter, la boucle FOR s'exécutera correctement; Si le tableau des résultats est vide, la boucle FOR ne s'exécutera pas.
  6. Quitte la boucle lorsque le nombre d'enregistrements extraits est inférieur à la taille attendue. N'oubliez pas de DBMS_SQL.CLOSE le curseur.

Votre corps de la boucle devrait ressembler à ceci:

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); 

Voir aussi Doing SQL from PL/SQL: Best and Worst Practices.

0

LIMIT CLAUSE PEUT VENIR À LA SAUVETAGE!

collections PL/SQL sont essentiellement des tableaux dans la mémoire, de sorte massives collections peuvent avoir un effet néfaste sur les performances du système en raison de la quantité de mémoire dont ils ont besoin.Dans certaines situations, il peut être nécessaire de diviser les données traitées en blocs pour rendre le code plus convivial pour la mémoire. Ce "découpage" peut être obtenu en utilisant la clause LIMIT de la syntaxe BULK COLLECT.

VOUS POUVEZ UTILISER LA LIMITATION DE CLAUSE APRÈS AVOIR COLLECTÉ EN CLAUSE POUR LIMITER VOTRE RS. APRÈS AVOIR DÉPASSÉ LA LIMITE, VOUS POUVEZ OBTENIR DES RANGÉES RESTANTES. VOIR CET ARTICLE http://www.dba-oracle.com/plsql/t_plsql_limit_clause.htm