IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Administration Oracle Discussion :

Une requête parsée plusieurs fois


Sujet :

Administration Oracle

  1. #1
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Femme

    Informations forums :
    Inscription : Septembre 2012
    Messages : 20
    Points : 14
    Points
    14
    Par défaut Une requête parsée plusieurs fois
    Bonjour,
    J'ai une requete qui utlise des variables bindé, alors que la requete est parsé tant de fois que de variable. ci-dessous la requete :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT  reference,date
     FROM commande 
    WHERE reference = :"VAR_B_0"
    Le TKPROF de cette requete est le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse      788      0.02       0.02          0          0          0           0
    Execute   1989      0.06       0.05          0          0          0           0
    Fetch     1989      0.08       0.07          0       7956          0        1989
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total     4766      0.18       0.15          0       7956          0        1989
    Alors je vois que la requete est parsé 788 fois, chose qui est anormale.

    Merci d'avance

  2. #2
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Mars 2010
    Messages
    536
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 536
    Points : 1 359
    Points
    1 359
    Par défaut
    Pourriez-vous poster la totalité du fichier TKPROF. Ou à la limite la partie qui reprend la requête en question.

  3. #3
    Expert éminent sénior Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Points : 11 252
    Points
    11 252
    Par défaut
    La requête est parsée 788 fois et exécutée 1989 fois. Le TKPROF enregistre les deux types des parse : soft et hard. Si le code à été écrit pour demander le parsing, TKPROF ne peut que l’enregistrer. Voire l'exemple ou la demande de parsing est placée d'une manière erronée à l'intérieur de la boucle.
    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
     
    declare
      last_name hr.employees.last_name%Type;
      ch        integer;
      r         integer;
    Begin
      ch := dbms_sql.open_cursor;
      for i in 1..100 Loop
        DBMS_SQL.PARSE(ch, 'Select last_name from hr.employees WHERE employee_id = :id',
                         DBMS_SQL.NATIVE);
        DBMS_SQL.BIND_VARIABLE(ch, ':id', i);
        r := DBMS_SQL.EXECUTE(ch);       
      End Loop;                 
      DBMS_SQL.CLOSE_CURSOR(ch);
    Exception
      When Others Then
        DBMS_SQL.CLOSE_CURSOR(ch);
        Raise;
    End;
    /
    et le TKPROF
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    Select last_name
    from
     hr.employees WHERE employee_id = :id
     
     
    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse      100      0.00       0.00          0          0          0           0
    Execute    100      0.00       0.09          0          0          0           0
    Fetch        0      0.00       0.00          0          0          0           0
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total      200      0.00       0.09          0          0          0           0

  4. #4
    Membre expérimenté Avatar de ojo77
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    Décembre 2010
    Messages
    680
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2010
    Messages : 680
    Points : 1 597
    Points
    1 597
    Par défaut
    En complément du message de Mnitu, si vous êtes en version 11R2, la requête est peut être sensible à la valeur de la variable ce qui peut expliquer plusieurs "hard parse"

  5. #5
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Femme

    Informations forums :
    Inscription : Septembre 2012
    Messages : 20
    Points : 14
    Points
    14
    Par défaut
    Citation Envoyé par Mohamed.Houri Voir le message
    Pourriez-vous poster la totalité du fichier TKPROF. Ou à la limite la partie qui reprend la requête en question.
    Merci pour ves feedback. je suis en version 11g. ci-joint le TKPROF complét.
    Fichiers attachés Fichiers attachés

  6. #6
    Membre averti
    Avatar de ora_home
    Homme Profil pro
    Consultant Oracle
    Inscrit en
    Février 2009
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Consultant Oracle
    Secteur : Finance

    Informations forums :
    Inscription : Février 2009
    Messages : 103
    Points : 376
    Points
    376
    Par défaut
    Bonjour,
    Pout le cas cité, Oracle faite un HARD PARSE pour chaque valeur de la variable "VAR_B_0".
    Alors si tu veux parser la requete une seule fois, pense à changer le paramétre : CURSOR_SHARING
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    alter system set cursor_sharing= FORCE;

  7. #7
    Expert éminent sénior Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Points : 11 252
    Points
    11 252
    Par défaut
    La présence des ":SYS_B_"X indique que vous est en CURSOR_SHARING = FORCE.
    Le message "Misses in library cache during parse: 0" indique des soft_parses.

  8. #8
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Femme

    Informations forums :
    Inscription : Septembre 2012
    Messages : 20
    Points : 14
    Points
    14
    Par défaut
    Citation Envoyé par mnitu Voir le message
    La présence des ":SYS_B_"X indique que vous est en CURSOR_SHARING = FORCE.

    Non mnitu, après avoir vérifié j'ai trouvé CURSOR_SHARING = SIMILAR

  9. #9
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Mars 2010
    Messages
    536
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 536
    Points : 1 359
    Points
    1 359
    Par défaut
    Citation Envoyé par devra Voir le message
    Non mnitu, après avoir vérifié j'ai trouvé CURSOR_SHARING = SIMILAR
    Hmmm.!!!!

    cursor_sharing = similar est très dangereux.

    Et je suppose que vous avez aussi des histogrammes sur certaines colonnes apparaisant dans vos requêtes (par exemple sur la colonne CDE_REFERENCE).

    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
     
    SELECT CDE_REF_PARENT  
    FROM
     DONNEE_COMMANDE WHERE CDE_REFERENCE=:"SYS_B_0"
     
     
    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse      363      0.01       0.01          0          0          0           0
    Execute    921      0.02       0.02          0          0          0           0
    Fetch      921      0.05       0.82        316       3684          0         921
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total     2205      0.09       0.86        316       3684          0         921
     
    Misses in library cache during parse: 0
    Optimizer mode: CHOOSE
    Parsing user id: 58
    Dans ce cas, Oracle non seulement remplace les valeurs mises en dur par des variables de liaisons (bind variable) mais décide aussi d'examiner cette valeur pour une re-optimisation à chaque remplacement de variable. Ce qui veut dire que grâce à la valeur du cursor_sharing = SIMILAR, votre requête est retrouvée dans la mémoire (library cache) ce qui explique le 0 de Misses in library cache during parse: 0, mais qu'à cause de cette valeur(SIMILAR) justement, chaque re-execution de votre requête est sujette (voir les conditions comme l'existence d'un histogramme sur la colonne ou un prédicat en range scan) à une ré-optimisation (un nouvel explain plan) ce qui expliquerait peut-être le nombre de parse assez elevé (40%) par rapport au nombre d'exécutions.

  10. #10
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Femme

    Informations forums :
    Inscription : Septembre 2012
    Messages : 20
    Points : 14
    Points
    14
    Par défaut
    Merci beaucoup Mohamed pour cette explication, et pour le temps que vous avez consacré pour l'analyse. Alors que ce que vous me proposé alors comme solution ?

  11. #11
    Expert éminent sénior Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Points : 11 252
    Points
    11 252
    Par défaut
    Citation Envoyé par devra Voir le message
    Non mnitu, après avoir vérifié j'ai trouvé CURSOR_SHARING = SIMILAR
    Oui en effet, ce que j'aurais voulu dire ce qu'il n'est pas EXACT. Donc il est FORCE ou bien SIMILAIRE. Et dans ce cas chaque changement de la valeur de la variable redemande le parsing.
    En fait vous avez plusiers requêtes de type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    SELECT  reference,date
     FROM commande 
    WHERE reference = 1
    /
    SELECT  reference,date
     FROM commande 
    WHERE reference = 1
    SELECT  reference,date
     FROM commande 
    WHERE reference = 2
    Qui sont toutes transformées en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    SELECT  reference,date
     FROM commande 
    WHERE reference = :"VAR_B_0"
    mais avec un parsing pour chaque changement de la valeur en dur.

    La solution est de mettre cursor_sharing à la valeur exact et de modifier l'application pour quelle utilise des variables de liaison (binding variable).

  12. #12
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Femme

    Informations forums :
    Inscription : Septembre 2012
    Messages : 20
    Points : 14
    Points
    14
    Par défaut
    Voilà le rapport TKPROF avec CURSOR_SHARING = FORCE.
    Que ce que vous proposez Monsieurs !!!
    Fichiers attachés Fichiers attachés

  13. #13
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Mars 2010
    Messages
    536
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 536
    Points : 1 359
    Points
    1 359
    Par défaut
    Citation Envoyé par devra Voir le message
    Merci beaucoup Mohamed pour cette explication, et pour le temps que vous avez consacré pour l'analyse. Alors que ce que vous me proposé alors comme solution ?
    1. Ne pas utiliser cursor_sharing= SIMILAR.
    2. Si vous êtes en environnement OLTP (Online Transactional Process) ne pas générer des histogrammes.

    Si votre application n'utilise pas correctement les variables de liaison vous pouvez à la limite utiliser le cursor_sharing= FORCE. J'ai eu à intervenir sur une application qui avait un problème de mémoire (SGA) si bien que parfois la seule solution dont on disposait c'était de stopper la base de données. J'ai résumé ceci dans cet article


    Edit : il semblerait que le cursor sharing FORCE n'a pas eu l'effet escompté.

    Pourriez-vous exécuter la requête suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    select sql_text
        , executions 
    from v$sql where executions < 2;

  14. #14
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Femme

    Informations forums :
    Inscription : Septembre 2012
    Messages : 20
    Points : 14
    Points
    14
    Par défaut
    Citation Envoyé par Mohamed.Houri Voir le message

    Si votre application n'utilise pas correctement les variables de liaison vous pouvez à la limite utiliser le cursor_sharing= FORCE. J'ai eu à intervenir sur une application qui avait un problème de mémoire (SGA) si bien que parfois la seule solution dont on disposait c'était de stopper la base de données. J'ai résumé ceci dans cet article


    Edit : il semblerait que le cursor sharing FORCE n'a pas eu l'effet escompté.

    Pourriez-vous exécuter la requête suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    select sql_text
        , executions 
    from v$sql where executions < 2;
    Merci beaucoup pour la réponse et pour l'article aussi, c'est très intéressant.

    ci-joint le résultats de la requête que vous avez demandé.
    Merci beaucoup
    Fichiers attachés Fichiers attachés

  15. #15
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Mars 2010
    Messages
    536
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 536
    Points : 1 359
    Points
    1 359
    Par défaut
    Citation Envoyé par devra Voir le message
    Merci beaucoup pour la réponse et pour l'article aussi, c'est très intéressant.

    ci-joint le résultats de la requête que vous avez demandé.
    Merci beaucoup
    Désolé, c'était plutôt un select count qu'il aurait fallu. Je vais essayer d'écrire ce que j'ai compris et ce que j'essaie de comprendre. Malgré le passage en cursor_sharing = FORCE, les choses ne se sont pas vraiment améliorées. Par exemple
    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    select TERM_EAN_FTT  
    from
     donnee_commande dc  inner join param_terminal pt on pt.term_id = dc.term_id 
      where CDE_REFERENCE = :"SYS_B_0"
     
     
    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse      338      0.01       0.00          0          0          0           0
    Execute    663      0.01       0.01          0          0          0           0
    Fetch      663      0.03       0.03          8       4641          0         663
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total     1664      0.07       0.06          8       4641          0         663
     
    select TERM_EAN_FTT  
    from
     donnee_commande dc  inner join param_terminal pt on pt.term_id = dc.term_id 
      where CDE_REFERENCE = :"SYS_B_0"
     
     
    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse      338      0.01       0.00          0          0          0           0
    Execute    663      0.01       0.01          0          0          0           0
    Fetch      663      0.03       0.03          8       4641          0         663
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total     1664      0.07       0.06          8       4641          0         663
     
    Misses in library cache during parse: 1
    Misses in library cache during execute: 1
    Avec en plus un Misses in library cache during execute: 1

    Ce qu'il faut faire maintenant c'est directement consulter la mémoire (v$sql) à la recheche du nombre d'instructions SQL qui ne sont pas re-exécutées (problème de variable de liaison) par rapport à ceux qui le sont. Pour cela vous pouvez faire ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    select count(1) from v$sql where executions < 2;
    select count(1) from v$sql;
    Une autre remarque aussi, chaque fichier trace contient l'instruction suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ALTER SESSION SET NLS_LANGUAGE= 'FRENCH' ....
    Ceci peut s'avèrer aussi un ingrédient à la re-optimisation (nouveau plan d'exécution).

    Egalement dans votre v$sql le nombre d'appel au package DBMS_STATS est impressionant. Etes-vous en train de calculer les statistiques maintenant.

    Enfin, il se peut que l'effet du cursor_sharing=FORCE ne soit pas immediat et qu'il faille attendre un peu; ou faire un flush du sharel pool; ceci n'est pas une bonne suggestion mais au vu de l'état de votre sharel pool !!!!

  16. #16
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Femme

    Informations forums :
    Inscription : Septembre 2012
    Messages : 20
    Points : 14
    Points
    14
    Par défaut
    Citation Envoyé par Mohamed.Houri Voir le message

    Egalement dans votre v$sql le nombre d'appel au package DBMS_STATS est impressionant. Etes-vous en train de calculer les statistiques maintenant.

    Enfin, il se peut que l'effet du cursor_sharing=FORCE ne soit pas immediat et qu'il faille attendre un peu; ou faire un flush du sharel pool; ceci n'est pas une bonne suggestion mais au vu de l'état de votre sharel pool !!!!
    Non, je calcule par les statisticques.
    pour le résultat des deux requetes les voilà :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    SQL> SELECT count(1) FROM v$sql WHERE executions < 2;
     
      COUNT(1)                                                                      
    ----------                                                                      
          1684                                                                      
     
    SQL> SELECT count(1) FROM v$sql;
     
      COUNT(1)                                                                      
    ----------                                                                      
          3451

  17. #17
    Expert éminent sénior Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Points : 11 252
    Points
    11 252
    Par défaut
    Citation Envoyé par devra Voir le message
    Voilà le rapport TKPROF avec CURSOR_SHARING = FORCE.
    Que ce que vous proposez Monsieurs !!!
    La solution est de mettre cursor_sharing à la valeur exact et de modifier l'application pour qu'elle utilise des variables de liaison (binding variable).

Discussions similaires

  1. [MySQL] Relancer une requête SQL plusieurs fois
    Par Steufa dans le forum PHP & Base de données
    Réponses: 9
    Dernier message: 16/06/2013, 19h33
  2. Sous-requête excutée plusieurs fois dans une requête
    Par sheridan31 dans le forum Oracle
    Réponses: 8
    Dernier message: 03/07/2006, 16h18
  3. une requête avec plusieurs INNER JOIN, cmt faire ?
    Par elhosni dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 10/01/2006, 17h55
  4. [SQL] Une requête dans plusieurs tables
    Par Anduriel dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 23/12/2005, 16h23
  5. Réponses: 2
    Dernier message: 10/07/2004, 17h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo