|
Publicité ' | ||||||||||||||||||||||||
|
|
#1 | ||
|
Nouveau Membre du Club
![]() Inscription : avril 2004 Messages : 102 ![]() |
Bonjour à tous,
Je vous embête un peu parce que j'ai un problème de performance avec un select qui dure 3h. Je suis pas très doué en optimisation et du coup je bloque un peu. Mon select se base sur 2 tables et 1 vue. La première table (table a) possède une volumétrie de 2millions de lignes la seconde table (table b) est petite (11 000 lignes) la vue est une vue assez simple et rapide à lire (table c) (20 000 lignes) Afin d'améliorer les performances du select, j'ai crée des index sur mes table : ma table b (index 1 : ALTACCT,TYPE index 2 : b.CNP_ACCT_MAGN, b.DESCR index 3 :CNP_ACCT_MAGN) sur ma table A j'ai crée également 4 index (index 1 : ALTACCT,PRODUCT index2 : CNP_MEGA_ENTITE,FISCAL_YEAR, ACCOUNTING_PERIOD, ALTACCT index 3 : ALTACCT et index 4 : PRODUCT) Le hic c'est que j'ai toujours un full scan sur ma table a que je n'arrive pas à optimiser. Du coup je pense que le trois heures est du à ce full scan. Ma question est donc : Est-il possible d’éviter un full scan sur ma table A ? Le SQL en question le voici Code :
Pour info je suis sous oracle 10.2.0.1.0 Auriez vous une piste vers laquelle je puisse m'orienter ? Merci beaucoup pour votre attention . |
||
|
|
00
|
|
|
#2 | ||
![]() ![]() |
Les plans d'exécution en XML c'est sympa, mais assez illisible sur le forum en l'état.
Exécutez ceci : Code :
__________________
Email : http://scr.im/waldar |
||
|
00
|
|
|
#3 | ||
|
Nouveau Membre du Club
![]() Inscription : avril 2004 Messages : 102 ![]() |
Effectivement
Je savais pas trop comment vous le mettre à disposition. Merci pour l'astuce. Voici mon plan d'éxecution Code :
Merci |
||
|
|
00
|
|
|
#4 | ||
|
Membre Expert
![]() Pacman PacmanBusiness analyst Inscription : juin 2004 Messages : 1 417 ![]() |
Salut,
Un full scan même sur 2 millions de lignes, ce n’est pas en soi le problème (en tous cas, ça ne justifie pas trois heures de traitement). Par contre, c’est ce qu’on fait de ces 2 millions de lignes qui est important. En l’occurrence dans ton plan, il commence par : Code :
La question qu’il faut se poser : quel est le groupe de conditions qui permet vraiment de restreindre la sélection sur la table A ? (Le filtre sur la table B peut être ?) Est-ce que l’index sur ALTACCT de la table A est très sélectif ?
__________________
(c'est ma photo) Paku, Paku ! Pour les jeunes incultes : non, je ne suis pas un pokémon... Le pacblog : http://pacmann.over-blog.com/ |
||
|
00
|
|
|
#5 | ||||
![]() ![]() Inscription : janvier 2004 Messages : 15 861 ![]() |
Si je ne m'abuse ceci :
Code :
Ceci : Code :
Serait-il possible de nous expliquer un peu le fonctionnel et donner des alias plus parlant que a, b,c ou d ? |
||||
|
|
00
|
|
|
#6 |
|
Expert Confirmé Sénior
![]() ![]() Marius NituIngénieur développement logiciels Inscription : octobre 2007 Messages : 3 311 ![]() |
C’est full scan à cause du Hash Join. C’est Hash Join parce que vous n’avez pas des filtres vraiment utiles ni sur la table A ni sur ta table B. Et comme de plus il y un outer join avec la vue matérialisé c et que cette vue filtre dans une sous-requête sur la table b il en déduit que le meilleur plan est le Hash Join (la Table A est grande la table B petite).
Je pense que vous devrez retravailler votre requête. |
|
|
10
|
|
|
#7 | ||||
|
Membre expérimenté
![]() Mohamed HouriInscription : mars 2010 Messages : 286 ![]() |
Bonjour,
De mon côté je vois trois points: (1) il serait mieux d'avoir l'explain plan en le prenant directement de la mémoire après execution de la query (en ajoutant le hint /*+ gather_plan_statistics) et en faisant ceci Code :
(1.a) quelle est l'operation la plus couteuse en temps (1.b) la précision des statistiques sur lesquelles se base le CBO (2) comme pacman l'a bien noté, la première opération effectuée par votre requete est l'operation 8 suivie de la 9 suivie de la 7 puis de la 13 etc... Les premières opérations à elles seules génèrent un volume important qu'il convient d'eliminer plutot, pour une meilleure performance (start small and keep small) (3) je vois que vous ne selectionnez aucun enregistrement de la table ps_cnp_prdct_nm_vw pourquoi alors la laisser dans la "from list". Est-ce la query suivante ne serait pas mieux Code :
Mohamed Houri |
||||
|
|
10
|
|
|
#8 | |||
|
Expert Confirmé Sénior
![]() ![]() Marius NituIngénieur développement logiciels Inscription : octobre 2007 Messages : 3 311 ![]() |
Citation:
Bref malheureusement, votre proposition ne marchera pas. |
|||
|
|
00
|
|
|
#9 | ||||||||
|
Nouveau Membre du Club
![]() Inscription : avril 2004 Messages : 102 ![]() |
Vraiment merci pour vos réponses,
Cela ma permis d'améliorer mon select voici mes actions : grâce à Pacmann j'ai remarqué que cette condition Code :
Ainsi j'ai remplacé la condition par (b.altacct au lieu de a.altacct) Code :
En ce qui concerne ton point 3, Mohamed, la table c j'en ai besoin juste en dessous Code :
En ce qui concerne ta remarque orafrance, fonctionnellement c'est un peu compliqué mais disons que la condition Code :
En fait ma table A est une table qui va me ramener des montants par compte (champ altacct) et sous compte (cnp_acct_magn). Pour un altacct je peux avoir 1 ou n cnp_acct_magn. Afin de choisir le bon sous compte je dois vérifier que le sous compte possede la norme lié à un produit (table c). cette transco sous compte norme est disponible grace à ma table d. Merci mnitu, pour retravailler la requête si malgré ces optimisations je ne gagne pas assez de temps, je pense que je m'orienterais faire votre proposition et là je m'aiderais d'un fonctionnel. Donc je relance mon traitement et je vous tiens informer Merci à tous pour vos remarques judicieuses |
||||||||
|
|
00
|
|
|
#10 | ||
![]() ![]() |
Une indentation et une syntaxe moderne permettent aussi de mieux s'y retrouver :
Code :
Par contre, l'histoire des EXISTS, NOT EXISTS, OR dans votre filtre, ressemble un peu à du bricolage, une jointure externe "pourrait" probablement faire la même chose. Je partage l'avis de mnitu quant à la ré-écriture de votre requête, en se basant sur le besoin fonctionnel initial.
__________________
Email : http://scr.im/waldar |
||
|
00
|
|
|
#11 | |
|
Membre Expert
![]() Pacman PacmanBusiness analyst Inscription : juin 2004 Messages : 1 417 ![]() |
Citation:
Je me permets juste de reposer la question : Une fois que tu as appliqué tous tes filtres sur la table B, ça correspond à combien de lignes de la table A ? (par le critère altacct) Si ça filtre très fort, il faut orienter le retravail de la requête (voire les hints en dernier recours) pour que le plan aille vers B -> filtre sur B -> NL JOIN sur A...
__________________
(c'est ma photo) Paku, Paku ! Pour les jeunes incultes : non, je ne suis pas un pokémon... Le pacblog : http://pacmann.over-blog.com/ |
|
|
00
|
|
|
#12 |
|
Expert Confirmé Sénior
![]() ![]() Marius NituIngénieur développement logiciels Inscription : octobre 2007 Messages : 3 311 ![]() |
Il ne peut pas à cause du C. Pour filtrer B il lui faut C mais C est lié à A. Avec une requête "normale" l'optimiseur aurait trouvé seul la réponse.
|
|
|
00
|
|
|
#13 |
|
Membre Expert
![]() ![]() Franck PachotDBA Oracle Inscription : novembre 2007 Messages : 703 ![]() |
Bonjour,
J'appuie la remarque de Mohamed puisque c'est le seul moyen de voir clairement ce qu'il se passe durant l'exécution. Parce que faire des hypothèses et des test empiriques, sur une requête qui prends 3 heures, ça peut durer longtemps... -> ajouter /*+ gather_plan_statistics */ après le premier select -> lancer la requête -> select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST')); ou mieux pour avoir les wait events en plus: -> exec DBMS_SESSION.SESSION_TRACE_ENABLE() -> lancer la requête -> disconnect -> tkprof sur la trace Cordialement, Franck.
__________________
A lire sur mon blog Oracle - Articles d'Experts des articles traduits en français de Jonathan Lewis, Tom Kyte, Doug Burns, Cary Millsap, Greg Rahn ...
|
|
01
|
|
|
#14 | |
|
Expert Confirmé Sénior
![]() ![]() Marius NituIngénieur développement logiciels Inscription : octobre 2007 Messages : 3 311 ![]() |
Citation:
De plus ce que vous appelez des hypothèses sont en réalité des conclusions. Ces conclusions sont issue de l'analyse de la requête. Et oui le plus dur dans l'analyse est de s'y mettre. C'est exactement ce que nous avons fait: @pacmann, @waldar, @orafrance, moi même en dans une certain mesure aussi @Mohamed.Houri. Voilà les étapes de cette analyse:
|
|
|
|
10
|
|
|
#15 | ||||||||
|
Membre expérimenté
![]() Mohamed HouriInscription : mars 2010 Messages : 286 ![]() |
Bonjour,
Il est vrai que connaitre le modèle est primordial dans le tuning des requêtes. J'ai essayé de bien faire dérouler toutes les opérations de 1 jusqu'à 17 en me concentrant sur les deux pavés (8 et 9 -->7) et (13,12,14,11--> 10) On voit bien que les deux opérations 7 et 10 conduisent les opérations filles (8,9) et (13,12,14,11) respectivement. Ce qui a retenu mon attention ce sont les opérations 13 et 10 Code :
Code :
En passant, je remarque que l'index 3 (altacct) sur la table a est inutile parce qu'il est couvert par l'index 1 (altacct, product). Comme toujours, il faut bien regarder la partie predicate, elle contient des informations importantes. Par exemple je vois ceci Code :
Vous avez un index sur les colonnes suivantes a.cnp_mega_entite, a.fiscal_year, a.accounting_period, a.altacct, Et vous faites un select des colonnes suivantes ,a.cnp_mega_entite ,a.fiscal_year ,a.accounting_period ,a.altacct ,SUM (a.amount) Pourquoi ne pas avoir créé l'index suivant (à la place de l'autre) a.altacct a.product a.cnp_mega_entite a.fiscal_year a.accounting_period a.amout Ainsi, vous pourriez peut-être eviter l'accès à la table ps_cnp_smldg_t28 a Quant à l'opération 10, elle indique qu'un push predicate a eu lieu sur la matérialized view. Juste pour voir quelle réaction va avoir votre query j'aurai essayé de l'executer avec le hint /*+ no_push_pred(c) */ Une autre remarque aussi sur l'utilisation des naming standards. Vos tables et vos indexes ne respectent pas un naming standard convenable. Pourtant c'est important dans la clarté des explain plans et de ceux qui veulent les lires Enfin, je vous conseille toujours d'extraire le vrai explain plan en utilisant Code :
J'espère qu'au moins ceci servira à inculquer une bonne approche de diagnostique des explains plan Bien à vous Mohamed Houri |
||||||||
|
|
00
|
|
|
#16 | ||
|
Expert Confirmé Sénior
![]() ![]() Marius NituIngénieur développement logiciels Inscription : octobre 2007 Messages : 3 311 ![]() |
Je pense que la requête suivante est équivalente à la requête initiale et bien sûr qu'elle devrait tourner un peu plus vite:
Code :
|
||
|
|
00
|
|
|
#17 |
![]() ![]() Inscription : janvier 2004 Messages : 15 861 ![]() |
Houaaaa
![]() Eventuellement, ça vaut le coup de tester le remplacement de : Code :
AND b.altact NOT IN (SELECT altact FROM ps_cnp_cpt_magn WHERE type = 'A') Code :
AND NOT EXISTS (SELECT 1 FROM ps_cnp_cpt_magn WHERE b.altact = altact AND type = 'A') |
|
|
01
|
|
|
#18 |
|
Nouveau Membre du Club
![]() Inscription : avril 2004 Messages : 102 ![]() |
Désolé pour le petit retard mais j'étais malade
![]() Bonne nouvelle, mon problème est résolu. Après les conseils de mnitu, on a revu la requête afin d'avoir des critéres réellement discriminants sur ma table a. De plus j'ai une modification importante sur la vue (table c) et j'ai donc aussi créer une snapshot. Merci à tous pour vos conseils ! |
|
|
00
|
|
|
#19 |
|
Invité de passage
![]() |
Je te proposerais d'utiliser un INTERSECT afin de supprimer les données que tu ne souhaites pas apparaitre dans la requête. Je te proposerais une autres requête mais je ne comprends pas très bien ce que tu souhaites.
J'ai eu une expérience similaire en voulant (cas d'opérateur téléphonique) sélectionner pour un jeu téléphonique tous les numéros (plus de 4millions) sauf ceux des employés. il a fait plus de 2 heures. Un intersect à fait moins de 2 minutes! Bon je réfléchis à ta requête et je te fais signe. |
|
00
|
|
|
#20 |
![]() ![]() |
Vous voulez parler de MINUS plutôt ?
__________________
Email : http://scr.im/waldar |
|
00
|
Copyright © 2000-2012 - www.developpez.com