|
Publicité ' | |||||||||||||||||||||||
|
|
#1 | ||||||||
![]() ![]() |
Bonjour à tous,
Dans le cadre d'un développement je dois extraire depuis une base de données des fichiers XML, afin de les envoyer à des tiers. Pour générer le XML, j'ai codé ce qu'il faut dans une vue en passant pas des objets créé pour le besoin : pas de soucis de ce côté là, ça répond plutôt bien. L'envoi des fichiers est piloté par une table tierce qui contient les méta-données. Là où je ne suis pas satisfait de mon process, c'est sur l'extraction de ces XML vers les fichiers. Certaines limitations me sont imposées :
Mon environnement est Oracle Database Enterprise Edition 11gR1 11.1.0.7, 64 bits qui opère sur Windows Server 2003. J'ai créé un jeu de test relativement simple pour illustrer tout ceci : Code :
Dans le code PL/SQL qui va suivre, ce qui me déplaît c'est que j'ai créé un premier curseur pour parcourir les éléments à envoyer, et à partir des données de celui-ci je vais chercher le bout de XML qui me convient. Avec ma volumétrie, effectuer la jointure à ce niveau en pur SQL est malheureusement trop coûteux, j'annule le teste après plus de trente minutes sans rien voir arriver. Dans ce code j'ai simulé la limitation à trois objets par fichier : Code :
Voici le contenu d'un fichier, qui est bien celui escompté : Code :
Ce n'est pas tellement l'écriture qui est lente, c'est vraiment d'aller chercher les bouts de XML un par un. C'est sur ce point qu'à mon avis le code peut être améliorer, je suis quasiment sûr que ce temps de traitement est divisible par deux ou trois. J'ai imaginé stocker tous mes identifiants dans une collection et la passer d'un coup à la vue, avec du XMLAgg afin de ne faire plus qu'un seul appel à ce niveau, mais je n'ai pas réussi à l'implémenter. Ayant relativement peu de pratique en pur PL/SQL, toutes expériences et idées sont les bienvenues ! Merci d'être parvenu au terme de ce long sujet. PS : Pour nettoyer votre environnement : Code :
__________________
Email : http://scr.im/waldar |
||||||||
|
00
|
|
|
#2 | ||
|
Expert Confirmé Sénior
![]() ![]() Marius NituIngénieur développement logiciels Inscription : octobre 2007 Messages : 3 311 ![]() |
Salut Waldar,
Oui travailler ligne par ligne n’est pas bon pour les performances. Si j’ai bien compris ton problème il te faut grouper les donnés des le départ et parcourir les données dans un seul passage. Code :
|
||
|
|
10
|
|
|
#3 |
![]() ![]() |
Tout simplement le trunc du row_number(), je n'y ai pas pensé.
Merci mnitu, je reviens avec le différentiel de temps de traitement.
__________________
Email : http://scr.im/waldar |
|
00
|
|
|
#4 |
![]() ![]() |
Aïe, même si l'idée est excellente, elle a mis le serveur sur les rotules.
Mon temps de référence est de treize minutes et après une demie-heure je n'ai toujours rien qui vient. Les CPU sont à 100%, je pense que le XMLAgg sur toutes les lignes est trop violent. Je vais regarder si je peux implémenter une solution intermédiaire, peut-être essayer de passer les id 100 par 100, mais là je retombe dans ma connaissance trop faible des collections. Ou alors si une autre idée surgit !
__________________
Email : http://scr.im/waldar |
|
00
|
|
|
#5 |
|
Expert Confirmé Sénior
![]() ![]() Marius NituIngénieur développement logiciels Inscription : octobre 2007 Messages : 3 311 ![]() |
C'est le fait du chercher ligne à ligne qui prends le plus du temps ou la concaténation des lobs ? C'est dans ce cas que le profil du traitement devrait indiquer dans où le temps passe et par conséquence comment il faut intervenir.
Quelle est la volumétrie de la table ? |
|
|
00
|
|
|
#6 | |||||
|
Membre Expert
![]() Inscription : août 2008 Messages : 1 271 ![]() |
Salut Waldar,
Alors effectivement nous ne savons pas encore lequel, du select dans la boucle ou de la concaténation des lobs, est le plus lent, mais au cas où le select dans la boucle soit en cause je propose une autre approche (mais franchement je ne sais pas ce que ça vaut, et vu que vous êtes tous les deux plus compétent que moi... j'ai de gros doutes...) Mon idée est, plutôt que de générer du XML en SQL et découper les fichiers en PL/SQL, pourquoi ne pas faire l'inverse... découper en SQL et générer le XML dans le code PL/SQL (à la manière du header et du footer déjà codés), au moins il n'y a plus de select dans une boucle. J'ai utilisé une variable globale pour "simuler" le paramètre v_nb_rows tel qu'il était utilisé dans le découpage, mais une modification assez simple te l'épargnera si tu préfères. Code :
Code :
Citation:
|
|||||
|
|
10
|
|
|
#7 |
![]() ![]() |
mnitu, je pensais perdre du temps sur l'appel un par un dans la vue XML à partir du curseur, mais justement ton test m'amène à penser qu'il faut jongler entre les deux coûts : l'appel récurrent ou la construction du XML directement par le moteur SQL.
J'ai lancé des tests unitaires en utilisant ton code, le XMLAgg sur le premier bloc dure environ cinq minutes alors que la sélection unitaire dans un CLOB global ne prend qu'une ou deux minutes. J'ai exécuté une trace sur mon traitement de référence, j'attends que le DBA sorte de réunion pour que je puisse l'analyser, puis j'en relancerai une sur le test unitaire du XMLAgg. Au niveau de la volumétrie, c'est plutôt faible au départ. Dans le modèle relationnel dédié, tables et index occupent 250 Mo. Le XML étant un langage verbeux, à partir de ce volume je génère un peu plus d'un Go de données. skuatamad, dans le test c'est faisable, malheureusement en vrai ma vue pour générer le XML fait plus de 200 lignes et possède sa petite complexité, ça va être difficile à réaliser.
__________________
Email : http://scr.im/waldar |
|
00
|
|
|
#8 | ||
|
Membre Expert
![]() Inscription : août 2008 Messages : 1 271 ![]() |
J'ai probablement été un peu violent en retirant tout le XML de la vue, mais si la requête "prédécoupe un peu" en fichier, la concaténation oppéré par le XMLAgg se fera facilement dans le PL/SQL et il n'y aura pas de requête dans la boucle.
Code :
|
||
|
|
10
|
|
|
#9 |
|
Expert Confirmé Sénior
![]() Inscription : juillet 2003 Messages : 3 437 ![]() |
A mon avis, ce qui est coûteux, c'est l'affectation sur CLOB et la concaténation. J'avais ce problème sur de la génération de SOAP XML.
Tant que tu peux utiliser du VARCHAR2 pour concaténer des chaines, fais le. Le Append sur ton CLOB global quand tu en as besoin. Sinon, tu as essayé uniquement en varchar2 pour remplir ton fichier ? Dernière ou première action : Mettre des traces (dbms_utility.get_time) entre chaque partie pour calculer le temps total de chaque instruction. C'est comme ça que j'avais vu que les append de CLOB étaient super longs.
__________________
More Code : More Bugs. Less Code : Less Bugs |
|
|
10
|
|
|
#10 | ||||||
|
Expert Confirmé Sénior
![]() ![]() Marius NituIngénieur développement logiciels Inscription : octobre 2007 Messages : 3 311 ![]() |
Salut Waldar,
Je pense que t’as peut être, un peut trop simplifié ton problème. Dans ce qui suit la table big (N fois select * from all_objects) contient presque 800 000 enregistrements. Une colonne id a été ajoutée et valorisée à partir du rownum pour devenir la clé primaire. La table big_pilote simule la table envoie (id, owner, object_type), clé primaire id. La vue donnes XML est Code :
Code :
Code :
|
||||||
|
|
10
|
|
|
#11 | ||||||||||||||
![]() ![]() |
Oui c'est fort possible, là où j'ai simplifié le problème c'est dans la vue qui retourne le XML, en réalité je récupère par objet entre 5000 et 150.000 caractères.
Je n'ai pas encore essayé de les découper en varchar2, c'est la prochaine étape. J'ai pu récupérer mes traces en attendant. Traitement de référence Requête du curseur : Code :
Code :
Code :
J'ai conservé l'idée de construire le fichier directement dans le curseur, et je fais un XMLAgg en utilisant ma plage d'identifiants récupérés directement à partir du curseur. Cette fois-ci je parviens à un résultat, mais environ deux fois moins rapide que le traitement de référence. Requête du curseur : Code :
Code :
Code :
Les temps pour un fichier (les autres sont dans les mêmes ordre de grandeur) en centièmes de secondes : Code :
__________________
Email : http://scr.im/waldar |
||||||||||||||
|
00
|
|
|
#12 | ||||
|
Expert Confirmé Sénior
![]() ![]() Marius NituIngénieur développement logiciels Inscription : octobre 2007 Messages : 3 311 ![]() |
Requêtes qui vont chercher le XML un par un :
Code :
Code :
Que voit-on dans les plans d'exécution ? |
||||
|
|
10
|
|
|
#13 | ||||
![]() ![]() |
L'explain plan me paraît correct.
Sur le traitement un à un, il fait ce qui est attendu, index unique scan + rowid access. Sur le traitement ensembliste, il fait un index full scan + rowid access + hash join... Par contre sur une de mes tables de mon modèle (que j'appelle aussi en XMLAgg dans ma vue), je me retrouve avec cette interprétation dans l'EXPLAIN PLAN de la trace : Code :
J'ai pu améliorer le traitement initial (edit : en fait temps similaire, mais code relativement plus simple) avec les idées récupérées ici + l'utilisation d'une collection. J'ai un peu moins de code pour la gestion des fichiers en créant dès le départ les bonnes plages : Code :
Merci à tous, toutes vos propositions m'ont bien aidées.
__________________
Email : http://scr.im/waldar |
||||
|
00
|
|
|
#14 |
|
Expert Confirmé Sénior
![]() ![]() Marius NituIngénieur développement logiciels Inscription : octobre 2007 Messages : 3 311 ![]() |
Je continu à penser que parcourir les données une seul fois devrait donner un meilleurs temps de réponse. Mais si le temps de réponse est acceptable c’est OK.
Par contre la solution qui détermine d’abord les plages des identifiants à extraire permet une optimisation plus intéressante encore qui via la parallélisassions des traitements d’écriture des fichiers. |
|
|
10
|
Copyright © 2000-2012 - www.developpez.com