Você pode acelerar este por uma ordem de magnitude com DBMS_LOB em vez de regular instr/substr:
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;
Caso de teste, processe CLOB de 60kb 10 vezes:
Sua função:
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
Função atualizada:
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
Atualizado para garantir que eles forneçam a mesma saída:
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
e atualizado
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