Oracle
 sql >> Base de données >  >> RDS >> Oracle

Dans Oracle, est-il possible de convertir une très grande chaîne (clob) séparée par une virgule en table avec de meilleures performances

Vous pouvez accélérer celui-ci d'un ordre de grandeur avec DBMS_LOB au lieu d'instr/substr normal :

CREATE OR REPLACE FUNCTION DROPME$STRSPLIT2 (
   P_STR     IN CLOB,
   P_DELIM   IN VARCHAR2 DEFAULT ';' ,
   P_LIKE    IN INT DEFAULT 0
)
   RETURN SYS.ODCIVARCHAR2LIST
AS
  L_DATA SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST ();
  L_STR  CLOB := P_STR || P_DELIM;  
  L_SUBSTR VARCHAR2(4000);
  L_STEP PLS_INTEGER := 0;
  L_THIS INT := 1;
  L_PREV INT := 0;
  L_END CHAR := CASE P_LIKE WHEN 0 THEN NULL ELSE '%' END;
BEGIN  
  LOOP
    L_STEP := L_STEP + 1;
    L_THIS := DBMS_LOB.INSTR(L_STR, P_DELIM, L_PREV + 1, 1);    
    EXIT WHEN L_THIS = 0;
    L_SUBSTR := 
    TRIM(
      DBMS_LOB.SUBSTR(
        L_STR, 
        L_THIS - L_PREV - 1,
        L_PREV + 1
      )
    );        
    L_PREV := L_THIS;    
    L_DATA.EXTEND();
    L_DATA(L_STEP) := L_SUBSTR || L_END;
  END LOOP;
  RETURN L_DATA;
END;

Scénario de test, traitez 60 Ko CLOB 10 fois :

Votre fonction :

18:15:50 SQL> l
  1  DECLARE
  2    VAL CLOB;
  3    RESULT SYS.ODCIVARCHAR2LIST;
  4  BEGIN
  5    SELECT C INTO VAL FROM DROPME$C;
  6    FOR I IN 1 .. 10 LOOP
  7      RESULT := DROPME$STRSPLIT1(VAL);
  8    END LOOP;
  9* END;
18:15:54 SQL> /

PL/SQL procedure successfully completed.

Elapsed: 00:00:11.56

Fonction mise à jour :

18:17:12 SQL> l
  1  DECLARE
  2    VAL CLOB;
  3    RESULT SYS.ODCIVARCHAR2LIST;
  4  BEGIN
  5    SELECT C INTO VAL FROM DROPME$C;
  6    FOR I IN 1 .. 10 LOOP
  7      RESULT := DROPME$STRSPLIT2(VAL);
  8    END LOOP;
  9* END;
18:17:14 SQL> /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.87

Mise à jour pour s'assurer qu'ils fournissent le même résultat :

18:20:08 SQL> l
  1  SELECT * FROM TABLE(
  2    DROPME$STRSPLIT1('a;b;c;d;f')
  3* )
18:20:10 SQL> /

COLUMN_VALUE
------------
a
b
c
d
f

et mis à jour

18:20:16 SQL> l
  1  SELECT * FROM TABLE(
  2    DROPME$STRSPLIT2('a;b;c;d;f')
  3* )
18:20:20 SQL> /

COLUMN_VALUE
------------
a
b
c
d
f