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 :
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 :
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 )
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 :
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
Partager