EDIT : message réintroduit suite à la panne de serveur
Bonjour,

J'ai une table contenant une colonne BFILE pointant vers des documents Word, Excel, PDF, etc sur un système de fichier. et je converti cette colonne en un contenu HTML pour une indexation future avec Oracle Text.

Ce que j'ai, une table contenant 3 millions d'enregistrements, le script de création volontairement réduit aux colonnes utiles pour cette discussion :
Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
CREATE TABLE DGTVISTA.VIS_DOCUMENTS_T (    DOC_ID           NUMBER(10)                   NOT NULL,    DOC_CLOB         CLOB,   DOC_BFILE        BFILE )
Une procédure qui boucle sur une plage de données de la table, convertissant pour chaque ligne la colonne DOC_BFILE en HTML dans la colonne DOC_CLOB via un convertisseur fourni par Oracle Text :

Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
 
CREATE OR REPLACE PROCEDURE DGTVISTA.fast_way_byrange_OLD (
   beginrownum   NUMBER,
   endrownum     NUMBER
)
IS
   ltimestamp_start   TIMESTAMP;
   ltimestamp_stop    TIMESTAMP;
   linterval_diff     INTERVAL DAY TO SECOND;
   n                  NUMBER                 := 0;
   c                  CLOB;
 
   TYPE ARRAY IS TABLE OF vis_documents_t%ROWTYPE;
 
   l_data             ARRAY;
 
   TYPE parent_rec IS RECORD (
      part_num    DBMS_SQL.number_table,
      part_name   DBMS_SQL.bfile_table
   );
 
   p_rec              parent_rec;
 
   CURSOR cur
   IS
      SELECT *
        FROM vis_documents_t
       WHERE doc_id IN (SELECT doc_id
                          FROM (SELECT a.*, ROWNUM rnum
                                  FROM (SELECT doc_id
                                          FROM vis_documents_t) a
                                 WHERE ROWNUM <= endrownum)
                         WHERE rnum >= beginrownum);
BEGIN
   ltimestamp_start := SYSTIMESTAMP;
   DBMS_OUTPUT.put_line (ltimestamp_start);
 
   OPEN cur;
 
   LOOP
      FETCH cur
      BULK COLLECT INTO l_data LIMIT 2000;
 
      FOR i IN 1 .. l_data.COUNT
      LOOP
         BEGIN
            ctx_doc.policy_filter ('dgt_policy', l_data (i).doc_bfile, c);
 
            UPDATE vis_documents_t
               SET doc_clob = c
             WHERE doc_id = l_data (i).doc_id;
         EXCEPTION
            WHEN OTHERS
            THEN
               NULL;
         END;
      END LOOP;
 
      EXIT WHEN cur%NOTFOUND;
   END LOOP;
 
   CLOSE cur;
 
   COMMIT;
   ltimestamp_stop := SYSTIMESTAMP;
   DBMS_OUTPUT.put_line (ltimestamp_stop);
   linterval_diff := ltimestamp_stop - ltimestamp_start;
   DBMS_OUTPUT.put_line (   CHR (10)
                         || LPAD ('=', 22, '=')
                         || CHR (10)
                         || '  Runtime Difference'
                         || CHR (10)
                         || LPAD ('=', 22, '=')
                        );
   DBMS_OUTPUT.put_line (   '     Days : '
                         || EXTRACT (DAY FROM linterval_diff)
                         || CHR (10)
                         || '    Hours : '
                         || EXTRACT (HOUR FROM linterval_diff)
                         || CHR (10)
                         || '  Minutes : '
                         || EXTRACT (MINUTE FROM linterval_diff)
                         || CHR (10)
                         || '  Seconds : '
                         || EXTRACT (SECOND FROM linterval_diff)
                        );
END fast_way_byrange_OLD;
/

Pour exécuter cette procédure, j'ai un script sous Unix qui lance en tâche de fond 5 fois un autre script (voir script suivant) responsable d'exécuter la procédure vue précédemment :

( NB : $DU $DP $DD sont les identifiants de connexions à la base de données Oracle, et les 2 derniers paramètres les bornes pour la procédure stockée vue précédemment )

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    (
./single_part_tab.sh $DU $DP $DD 0 50000
) &
 
(
./single_part_tab.sh $DU $DP $DD 50001 100000
) &
 
(
./single_part_tab.sh $DU $DP $DD 100001 150000
) &
 
(
./single_part_tab.sh $DU $DP $DD 150001 200000
) &
 
(
./single_part_tab.sh $DU $DP $DD 200001 250000
) &
 
wait
Le script single_part_tab.sh responsable d'appeler la procédure stockée vue au dessus :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
    sqlplus -S $1/$2@$3 << EOF > logs/log_part_tab_$4_to_$5.log
SET SERVEROUTPUT ON
TIMING START mytimer_single_part_tab
exec fast_way_byrange ($4,$5);
TIMING STOP mytimer_part_tab
exit
EOF
J'ai lancé le tout hier (avec les plages de données de ce post) et le traitement a duré plus de 9 heures, pour seulement 250 000 enregistrements convertis en HTML, sachant que j'en ai 3 millions au final ça risque de prendre du temps, trop de temps.

Aussi, auriez vous des idées ? des conseils ? des corrections à apporter ? pour que ce traitement soit optimisé.

Et si vous voyez quelque chose de mauvais dans mon code merci d'avance pour vos précisions.

Merci d'avance