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

SQL Oracle Discussion :

Plan d'exécution différent IN ou NOT IN [10g]


Sujet :

SQL Oracle

  1. #1
    Membre actif
    Inscrit en
    Avril 2006
    Messages
    702
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 702
    Points : 289
    Points
    289
    Par défaut Plan d'exécution différent IN ou NOT IN
    Bonjour a tous,

    (oracle 10G -- Linux 5)
    petit casse tête de vendredi, j'ai cette requête:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     SELECT 
            P.ID,
            P.ES,
            FN.GR,
            P.PVP
     FROM PROD P
     INNER JOIN FAM FN ON FN.GEN=P.GEN
     WHERE P.ID NOT LIKE '00%' 
     AND decode(P.ID,'06570074','770', decode(P.ID,'73268025','229', decode(P.ID,'63210660','208', decode(P.ID,'61154352','150', decode(P.ID,'06553572','753', decode(P.ID,'06563389','763', DECODE(substr(P.ID,3,1), '9', P.FAM||SUBSTR(P.ID,4,2), '8', P.FAM||SUBSTR(P.ID,4,2), '7', P.FAM||SUBSTR(P.ID,4,2), SUBSTR(P.ID,3,3) ) ) ) ) ) ) ) = FN.ID  
     AND P.ID NOT IN('53006262','53328461','53328462');

    Telle que vous la voyez, cette requête génère un full scan sur la table PROD, bien que cette table possède une PK sur le champs ID.
    Si vous changez le NOT IN de la fin par un IN, la PK est prise en compte et de 60 000 GETS ça passe a 8... Le résultat n'est plus le même bien sur, et je voudrais savoir s'il existe un moyen d'utiliser la PK avec le NOT IN.

    quelqu'un a une idée?
    Moi je sèche, j'ai pensé a un index INVERSE, mais comme la tabla est utilisée pour d'autres traitements si j'inverse l'index, j'ai peur que cela dégrade d'autres requêtes.

    D'avance merci pour toute suggestion.

  2. #2
    Membre éclairé Avatar de Arkhena
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 552
    Points : 769
    Points
    769
    Par défaut
    Bonjour,

    Si l'optimiseur Oracle n'utilise pas la PK, c'est qu'il considère que c'est plus coûteux que de faire un fullscan... Et on le comprend!

    Vous utilisez un PK, donc des enregistrements tous différents -> très grande disparité de valeur

    Dans le premier cas, vous lui demandez de récupérer toutes les données sauf 3 : il est plus intéressant de faire un full scan!

    Dans le deuxième cas, vous lui demandez de ne récupérer que 3 valeurs parmi toutes vos données : il est plus intéressant de passer par l'index...

    Un full scan n'est pas forcément un problème de performances et passer par un indes peut même être moins bon qu'un full scan en terme de performances...

    Cordialement,

    Arkhena

  3. #3
    Membre actif
    Inscrit en
    Avril 2006
    Messages
    702
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 702
    Points : 289
    Points
    289
    Par défaut
    Bonjour,
    oui je suis d'accord. C'est donc la logique même de la requête qu'il faut changer.
    Une sortie serait de recuperer aussi ces 3 valeurs, ce qui permetrais d'utiliser la PK, et ensuite de faire un delete dans le package... Un delete de 3 registres etant beaucoup moins couteux que le fullscan. Dans ce cas, le full scan est un probleme car la table est immense, et les gets sont elevés.

    Merci pour tout, et si vous voyez une autre forme de faire, ça m'interesse

  4. #4
    Membre éclairé Avatar de Arkhena
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 552
    Points : 769
    Points
    769
    Par défaut
    Bonjour,

    Je crains de manquer d'information pour pouvoir vous donner quelque chose de plus précis...

    Cependant, je pense que vous avez des gros soucis avec votre modèle de données.

    - J'ai l'impression que vous stockez l'id (qui il me semble est la clé primaire de la table prod) sous forme de chaîne de caractères (alors que vous stockez des nombres dedans).
    Il serait plus efficace d'utiliser une clé primaire numérique.(cf http://sqlpro.developpez.com/cours/clefs/)

    - Pourquoi être obligé de faire des décodes dans la jointure entre la table FAM et la table PROD ? La condition de jointure ne suffit pas ?

    Cordialement,

    Arkhena

  5. #5
    Membre actif
    Inscrit en
    Avril 2006
    Messages
    702
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 702
    Points : 289
    Points
    289
    Par défaut
    Bonjour
    oui je suis d'accord aussi, il s'agit de la relation entre le dba et les developpeurs... J'ai remarquer ce detail du varchar sur le champ ID et ça m'a etonné aussi. C'est dans la liste des trucs a voir avec eux.

    Pour le decode, c'est pareil je dois voir avec les dev. Cependant, j'ai essayé la requête en commentant le decode et le full scan reste.. C'est bien le NOT IN qui me joue un mauvais plan.

    On gagnera beaucoup en changant l'ID de varchar a number? je vais lire le lien que tu as envoyé.
    Merci encore !

  6. #6
    Membre actif
    Inscrit en
    Avril 2006
    Messages
    702
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 702
    Points : 289
    Points
    289
    Par défaut
    Re bonjour,
    dans le cas ou je dois changer l'ID de varchar2 a number... Existe t'il une note metalink pour ça? je demande car j'ai pas encore l'acces.

    D'avance merci

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2010
    Messages
    412
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 412
    Points : 807
    Points
    807
    Par défaut
    Sinon avant de tout changer, essayez donc de créer un autre index sur votre colonne avec TO_NUMBER(votre_valeur).

  8. #8
    Membre chevronné
    Inscrit en
    Août 2009
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 1 073
    Points : 1 806
    Points
    1 806
    Par défaut
    Accessoirement :
    - Pourquoi faire autant de DECODE ? Deux suffiraient et c'est plus lisible.

    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
     
     SELECT 
            P.ID,
            P.ES,
            FN.GR,
            P.PVP
     FROM PROD P
     INNER JOIN FAM FN ON FN.GEN=P.GEN
     WHERE P.ID NOT LIKE '00%' 
     AND decode(P.ID
    		,'06570074','770'
    		,'73268025','229'
    		,'63210660','208'
    		,'61154352','150'
    		,'06553572','753'
    		,'06563389','763'
    		,DECODE(  substr(P.ID,3,1)
    				, '9' ,P.FAM||SUBSTR(P.ID,4,2)
    				, '8' ,P.FAM||SUBSTR(P.ID,4,2)
    				, '7' ,P.FAM||SUBSTR(P.ID,4,2)
    				, SUBSTR(P.ID,3,3)  
    				)
    		)= FN.ID  
     AND P.ID NOT IN('53006262','53328461','53328462');

    -Vous pourriez créer une colonne calculée, avec index, qui servirait à la liaison.

  9. #9
    Expert éminent
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Points : 6 446
    Points
    6 446
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    je voudrais savoir s'il existe un moyen d'utiliser la PK avec le NOT IN.
    Une sortie serait de recuperer aussi ces 3 valeurs, ce qui permetrais d'utiliser la PK
    la table est immense
    Si la requête récupère toutes les lignes d'une table immense sauf 3, le full scan est probablement la bonne solution. Lorsque vous utilisez IN au lieu de NOT IN, vous allez chercher seulement 3 lignes: l'accès par index est parfait.
    Mais si vous voulez presque toutes les lignes de PROD passer par un index serait catastrophique.

    Sinon, à propos de:
    Citation Envoyé par Arkhena Voir le message
    Il serait plus efficace d'utiliser une clé primaire numérique.(cf http://sqlpro.developpez.com/cours/clefs/)
    Non. en tout cas pas sous Oracle. Le type de donnée est déterminé par l'analyse. Ici il semble que les zéros devant sont significatifs: NOT LIKE '00%'

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SQL> select dump('53006262'),dump(53006262) from dual;
     
    DUMP('53006262')                      DUMP(53006262)
    ------------------------------------- ---------------------------
    Typ=96 Len=8: 53,51,48,48,54,50,54,50 Typ=2 Len=5: 196,54,1,63,63
    Pensez-vous que comparer 5 octets au lieu de 8 fera une grosse différence ?

    Cordialement,
    Franck.

  10. #10
    Membre actif
    Inscrit en
    Avril 2006
    Messages
    702
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 702
    Points : 289
    Points
    289
    Par défaut
    Bonjour a tous,

    merci pour tous vos commentaires. Donc ici le full scan est inevitable,, il s'agit d'un select pour faire un insert. Donc pour optimiser le procedure qui en definitive est un insert into, je vais essayer de:

    - Desactiver la PK sur la table ou je fais l'insert
    - passer la table a NOLOGGING
    - ajouter un hint append
    - A la fin de l'insert, reactiver la PK et le LOGGING
    - Calculer stats

    Qu'en pensez vous?

  11. #11
    Expert éminent
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Points : 6 446
    Points
    6 446
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    ajouter un hint append
    Oui s'il n'y a jamais de delete (sinon l'espace libre ne sera pas réutilisé).
    passer la table a NOLOGGING
    Oui mais les données ne seront pas recoverable avant le prochain backup.
    - Desactiver la PK sur la table ou je fais l'insert
    - A la fin de l'insert, reactiver la PK et le LOGGING
    A tester. En APPEND, ce n'est peut-être pas nécessaire (les index son maintenus à la fin).
    - Calculer stats
    Oui.

    Cordialement,
    Franck.

  12. #12
    Membre actif
    Inscrit en
    Avril 2006
    Messages
    702
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 702
    Points : 289
    Points
    289
    Par défaut
    Salut

    je viens de regarder le procédure, les données s’insèrent dans une table TMP
    et juste avant il y a un truncate:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    execute immediate 'TRUNCATE TABLE TMP_ARTICULOS_WORKING';
    Après ce truncate il y a l'insert (select)
    Je peux changer le truncate par un drop et create de cette table ? ça arrange le problème que tu commentais de la perte d'espace ?
    D'avance merci

  13. #13
    Expert éminent
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Points : 6 446
    Points
    6 446
    Billets dans le blog
    1
    Par défaut
    Non non. C'est très bien le truncate. Ca vide tout en baissant le high water mark. Donc l'append sera optimal.

  14. #14
    Membre actif
    Inscrit en
    Avril 2006
    Messages
    702
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 702
    Points : 289
    Points
    289
    Par défaut
    ok

    A tout hazard, je poste la query compete ici juste pour si quelqu'un detecte un astuce pour ameliorer:

    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
    32
    33
    set autotrace traceonly;
     
    SELECT 
            P.ID,
            P.ESTILO,
            FN.GRUPO,
            P.PVP PVP,
            CALCULO_REBAJA(P.ID) REBAJA,
            N.DESCRIPCION,
            N.IDIOMA,
            SYSDATE,
            NULL, MAX(A.BLOQUE),
            MIN(PRPR.PRIORIDAD),
            N.DESCRIPCION_CORTA
     FROM PRODUCTOS P
     INNER JOIN PRODUCTO_ALMACEN PA ON P.ID = PA.PRODUCTO AND PA.ALMACEN = '001'
     INNER JOIN FAMILIA_NOMBRES FN ON FN.GENERO=P.GENERO
     INNER JOIN NOMBRES N ON P.ID = N.PRODUCTO 
     INNER JOIN ARTICULOS A ON SUBSTR(A.ID,0,8) = P.ID
     INNER JOIN ARTICULOS_ALMACEN AA ON AA.ID = A.ID AND AA.ALMACEN = '001' AND TO_NUMBER(AA.STOCK_REAL) > 0 AND AA.FECHA_BAJA IS NULL
     LEFT JOIN PRODUCTO_PRIORIDAD PRPR ON PRPR.PRODUCTO = P.ID
     WHERE(
    	   (A.BLOQUE IN (select bloque from ALMACENES_BLOQUES where almacen = '001'))
    	   OR 
    	   (A.PRODUCTO LIKE '9%')
    		OR 
    	   (A.PRODUCTO in (select id from AVANCE_BLOQUE where almacen = '001')) 
      )
     AND SUBSTR(A.ID,0,8) = P.ID
     AND P.ID NOT LIKE '00%' 
     AND decode(P.ID,'06570074','770', decode(P.ID,'73268025','229', decode(P.ID,'63210660','208', decode(P.ID,'61154352','150', decode(P.ID,'06553572','753', decode(P.ID,'06563389','763', DECODE(substr(P.ID,3,1), '9', P.FAMILIA||SUBSTR(P.ID,4,2), '8', P.FAMILIA||SUBSTR(P.ID,4,2), '7', P.FAMILIA||SUBSTR(P.ID,4,2), SUBSTR(P.ID,3,3) ) ) ) ) ) ) ) = FN.ID 
     AND P.ID not in('53006262','53328461','53328462')
     GROUP BY P.ID, P.ESTILO, FN.GRUPO, P.PVP, N.DESCRIPCION, N.IDIOMA, N.DESCRIPCION_CORTA;
    Le plan est:
    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
    Plan de Ejecuci¾n
    ----------------------------------------------------------
    Plan hash value: 3066295558
     
    --------------------------------------------------------------------------------------------------------------
    | Id  | Operation                            | Name                  | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                     |                       |   162 | 27864 |  3656   (1)| 00:00:44 |
    |   1 |  HASH GROUP BY                       |                       |   162 | 27864 |  3656   (1)| 00:00:44 |
    |*  2 |   FILTER                             |                       |       |       |            |       |
    |   3 |    NESTED LOOPS                      |                       |       |       |            |       |
    |   4 |     NESTED LOOPS                     |                       |  1352 |   227K|  3655   (1)| 00:00:44 |
    |   5 |      NESTED LOOPS OUTER              |                       |   158 | 16906 |  2113   (1)| 00:00:26 |
    |   6 |       NESTED LOOPS                   |                       |   158 | 14852 |  2110   (1)| 00:00:26 |
    |*  7 |        HASH JOIN                     |                       |   175 | 14175 |  1935   (1)| 00:00:24 |
    |*  8 |         TABLE ACCESS FULL            | FAMILIA_NOMBRES       |   577 |  5193 |     3   (0)| 00:00:01 |
    |*  9 |         HASH JOIN                    |                       |   394 | 28368 |  1931   (1)| 00:00:24 |
    |  10 |          NESTED LOOPS                |                       |       |       |            |       |
    |  11 |           NESTED LOOPS               |                       |   396 | 20988 |  1722   (1)| 00:00:21 |
    |* 12 |            TABLE ACCESS FULL         | ARTICULOS_ALMACEN     |   396 | 11088 |   930   (1)| 00:00:12 |
    |* 13 |            INDEX UNIQUE SCAN         | PK_ARTICULOS          |     1 |       |     1   (0)| 00:00:01 |
    |  14 |           TABLE ACCESS BY INDEX ROWID| ARTICULOS             |     1 |    25 |     2   (0)| 00:00:01 |
    |* 15 |          TABLE ACCESS FULL           | PRODUCTOS             | 62577 |  1161K|   208   (1)| 00:00:03 |
    |* 16 |        INDEX UNIQUE SCAN             | PK_PRODUCTO_ALMACEN   |     1 |    13 |     1   (0)| 00:00:01 |
    |  17 |       TABLE ACCESS BY INDEX ROWID    | PRODUCTO_PRIORIDAD    |     1 |    13 |     1   (0)| 00:00:01 |
    |* 18 |        INDEX UNIQUE SCAN             | PK_PRODUCTO_PRIORIDAD |     1 |       |     0   (0)| 00:00:01 |
    |* 19 |      INDEX RANGE SCAN                | PK_NOMBRES            |     9 |       |     2   (0)| 00:00:01 |
    |  20 |     TABLE ACCESS BY INDEX ROWID      | NOMBRES               |     9 |   585 |    10   (0)| 00:00:01 |
    |* 21 |    INDEX UNIQUE SCAN                 | PK_ALMACENES_BLOQUES  |     1 |     7 |     0   (0)| 00:00:01 |
    |* 22 |    INDEX UNIQUE SCAN                 | PK_AVANCE_BLOQUE      |     1 |    13 |     1   (0)| 00:00:01 |
    --------------------------------------------------------------------------------------------------------------
    Les stats sont pas belles:
    Apres la segonde execution:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    EstadÝsticas
    ----------------------------------------------------------
              1  recursive calls
              4  db block gets
          19821  consistent gets
           7882  physical reads
              0  redo size
        2660430  bytes sent via SQL*Net to client
          18101  bytes received via SQL*Net from client
           1600  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
          23982  rows processed
    De cette requete ce qui me chifonne le plus c'est cette partie:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    WHERE(
    	   (A.BLOQUE IN (select bloque from ALMACENES_BLOQUES where almacen = '001'))
    	   OR 
    	   (A.PRODUCTO LIKE '9%')
    		OR 
    	   (A.PRODUCTO in (select id from AVANCE_BLOQUE where almacen = '001')) 
      )
    La si l'on change le OR pas un AND tous les full scan disparaisses.
    Donc je crois que c'est ici l'endroit mal ecrit.
    J'avais pensé remplacer le OR avec un UNION ALL mais j'arrive pas a sortir le code...

    Selon le plan, le cost CPU du full scan de la table PRODUCTOS est de 208
    alors que le full scan de la table articulos_almacen est de 930 alors que les row recuperées sont beaucoup moindre... Je comprends pas bien.
    Pour ameliorer la prformence, et sachant que le full scan sur productos est obligé, que puis je faire pour degager le full scan de la table articulos_almacen?
    Dans la requete j'ai ceci.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     INNER JOIN ARTICULOS_ALMACEN AA ON AA.ID = A.ID AND AA.ALMACEN = '001' AND TO_NUMBER(AA.STOCK_REAL) > 0 AND AA.FECHA_BAJA IS NULL
    D'avance merci, ne perdez pas de temps a depiauter cette requete, si rien d'evident ne saute aux yeux.

  15. #15
    Membre actif
    Inscrit en
    Avril 2006
    Messages
    702
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 702
    Points : 289
    Points
    289
    Par défaut
    Bonjour
    je crois que j'ai compris.
    La tabla articulos_almacen produit un full scan car y'a pas de selectivité sur cette table, le contenu est:

    ALMACEN COUNT(1)
    720 128289
    075 102047
    052 163072
    001 103701
    400 161976

    donc vu que je lu icolle un almacen='001' il ramene 103701 rows ... Le cost est donc ce que coute a oracle de recuperer ces files. Vous confirmez?
    Peu etre que dans ce cas il vaux mieux virer l'index non?

    L'index est de type PK combiné:
    PLAIN PK_ARTICULOS_ALMACEN Y NO 1 ID Asc 1 PLAIN PK_ARTICULOS_ALMACEN Y NO 1 ALMACEN Asc 2

  16. #16
    Expert éminent
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Points : 6 446
    Points
    6 446
    Billets dans le blog
    1
    Par défaut
    Bonjour,
    Le plan d'exécution donne les estimations (de lignes, de coût) mais ces estimations ne sont peut être pas bonne.
    Voici comment avoir les stats réelles d'exécution:
    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
    32
    33
    34
    SELECT /*+ gather_plan_statistics */
            P.ID,
            P.ESTILO,
            FN.GRUPO,
            P.PVP PVP,
            CALCULO_REBAJA(P.ID) REBAJA,
            N.DESCRIPCION,
            N.IDIOMA,
            SYSDATE,
            NULL, MAX(A.BLOQUE),
            MIN(PRPR.PRIORIDAD),
            N.DESCRIPCION_CORTA
     FROM PRODUCTOS P
     INNER JOIN PRODUCTO_ALMACEN PA ON P.ID = PA.PRODUCTO AND PA.ALMACEN = '001'
     INNER JOIN FAMILIA_NOMBRES FN ON FN.GENERO=P.GENERO
     INNER JOIN NOMBRES N ON P.ID = N.PRODUCTO 
     INNER JOIN ARTICULOS A ON SUBSTR(A.ID,0,8) = P.ID
     INNER JOIN ARTICULOS_ALMACEN AA ON AA.ID = A.ID AND AA.ALMACEN = '001' AND TO_NUMBER(AA.STOCK_REAL) > 0 AND AA.FECHA_BAJA IS NULL
     LEFT JOIN PRODUCTO_PRIORIDAD PRPR ON PRPR.PRODUCTO = P.ID
     WHERE(
           (A.BLOQUE IN (SELECT bloque FROM ALMACENES_BLOQUES WHERE almacen = '001'))
           OR 
           (A.PRODUCTO LIKE '9%')
            OR 
           (A.PRODUCTO IN (SELECT id FROM AVANCE_BLOQUE WHERE almacen = '001')) 
      )
     AND SUBSTR(A.ID,0,8) = P.ID
     AND P.ID NOT LIKE '00%' 
     AND decode(P.ID,'06570074','770', decode(P.ID,'73268025','229', decode(P.ID,'63210660','208', decode(P.ID,'61154352','150', decode(P.ID,'06553572','753', decode(P.ID,'06563389','763', DECODE(substr(P.ID,3,1), '9', P.FAMILIA||SUBSTR(P.ID,4,2), '8', P.FAMILIA||SUBSTR(P.ID,4,2), '7', P.FAMILIA||SUBSTR(P.ID,4,2), SUBSTR(P.ID,3,3) ) ) ) ) ) ) ) = FN.ID 
     AND P.ID NOT IN('53006262','53328461','53328462')
     GROUP BY P.ID, P.ESTILO, FN.GRUPO, P.PVP, N.DESCRIPCION, N.IDIOMA, N.DESCRIPCION_CORTA;
     
    select * from dbms_xplan.display_cursor('','','allstats last');
    Cordialement,
    Franck.

  17. #17
    Membre actif
    Inscrit en
    Avril 2006
    Messages
    702
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 702
    Points : 289
    Points
    289
    Par défaut
    Aie, ça me donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SQL> select * from dbms_xplan.display_cursor('','','allstats last');
    select * from dbms_xplan.display_cursor('','','allstats last')
                                           *
    ERROR en lÝnea 1:
    ORA-00933: comando SQL no terminado correctamente
    j'essais avec ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SQL> SET LINESIZE 130
    SQL> SET PAGESIZE 0
    SQL> SELECT * FROM table(DBMS_XPLAN.DISPLAY);
    Error: cannot fetch last explain plan from PLAN_TABLE

  18. #18
    Membre actif
    Inscrit en
    Avril 2006
    Messages
    702
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 702
    Points : 289
    Points
    289
    Par défaut
    Ok j'ai fait un alter session set statistics_level=ALL
    et ça donne ceci:

    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
    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
    Plan hash value: 3066295558
     
    ----------------------------------------------------------------------------------------------------------------------------------
    ---------------------------------------------
     
    | Id  | Operation                            | Name                  | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
    Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
     
    ----------------------------------------------------------------------------------------------------------------------------------
    ---------------------------------------------
     
    |   0 | SELECT STATEMENT                     |                       |      1 |        |  23982 |00:00:04.07 |     206K|   3649 |
       255 |       |       |          |         |
     
    |   1 |  HASH GROUP BY                       |                       |      1 |    162 |  23982 |00:00:04.07 |     206K|   3649 |
       255 |  5112K|  1903K| 3242K (1)|    3072 |
     
    |*  2 |   FILTER                             |                       |      1 |        |  91542 |00:00:03.79 |     206K|   3394 |
         0 |       |       |          |         |
     
    |   3 |    NESTED LOOPS                      |                       |      1 |        |    145K|00:00:03.52 |     204K|   3394 |
         0 |       |       |          |         |
     
    |   4 |     NESTED LOOPS                     |                       |      1 |   1352 |    145K|00:00:02.25 |   61472 |   3394 |
         0 |       |       |          |         |
     
    |   5 |      NESTED LOOPS OUTER              |                       |      1 |    158 |  12381 |00:00:01.73 |   44243 |   3394 |
         0 |       |       |          |         |
     
    |   6 |       NESTED LOOPS                   |                       |      1 |    158 |  12381 |00:00:01.61 |   44213 |   3394 |
         0 |       |       |          |         |
     
    |*  7 |        HASH JOIN                     |                       |      1 |    175 |  12381 |00:00:01.48 |   27247 |   3394 |
         0 |  1180K|  1180K| 1289K (0)|         |
     
    |*  8 |         TABLE ACCESS FULL            | FAMILIA_NOMBRES       |      1 |    577 |    577 |00:00:00.01 |       6 |      0 |
         0 |       |       |          |         |
     
    |*  9 |         HASH JOIN                    |                       |      1 |    394 |  12381 |00:00:01.37 |   27241 |   3394 |
         0 |  1415K|  1192K| 2031K (0)|         |
     
    |  10 |          NESTED LOOPS                |                       |      1 |        |  12381 |00:00:01.03 |   26468 |   3394 |
         0 |       |       |          |         |
     
    |  11 |           NESTED LOOPS               |                       |      1 |    396 |  12381 |00:00:00.93 |   14087 |   3394 |
         0 |       |       |          |         |
     
    |* 12 |            TABLE ACCESS FULL         | ARTICULOS_ALMACEN     |      1 |    396 |  12381 |00:00:00.81 |    3454 |   3394 |
         0 |       |       |          |         |
     
    |* 13 |            INDEX UNIQUE SCAN         | PK_ARTICULOS          |  12381 |      1 |  12381 |00:00:00.06 |   10633 |      0 |
         0 |       |       |          |         |
     
    |  14 |           TABLE ACCESS BY INDEX ROWID| ARTICULOS             |  12381 |      1 |  12381 |00:00:00.05 |   12381 |      0 |
         0 |       |       |          |         |
     
    |* 15 |          TABLE ACCESS FULL           | PRODUCTOS             |      1 |  62577 |  64182 |00:00:00.08 |     773 |      0 |
         0 |       |       |          |         |
     
    |* 16 |        INDEX UNIQUE SCAN             | PK_PRODUCTO_ALMACEN   |  12381 |      1 |  12381 |00:00:00.07 |   16966 |      0 |
         0 |       |       |          |         |
     
    |  17 |       TABLE ACCESS BY INDEX ROWID    | PRODUCTO_PRIORIDAD    |  12381 |      1 |      4 |00:00:00.07 |      30 |      0 |
         0 |       |       |          |         |
     
    |* 18 |        INDEX UNIQUE SCAN             | PK_PRODUCTO_PRIORIDAD |  12381 |      1 |      4 |00:00:00.03 |      26 |      0 |
         0 |       |       |          |         |
     
    |* 19 |      INDEX RANGE SCAN                | PK_NOMBRES            |  12381 |      9 |    145K|00:00:00.24 |   17229 |      0 |
         0 |       |       |          |         |
     
    |  20 |     TABLE ACCESS BY INDEX ROWID      | NOMBRES               |    145K|      9 |    145K|00:00:00.61 |     143K|      0 |
         0 |       |       |          |         |
     
    |* 21 |    INDEX UNIQUE SCAN                 | PK_ALMACENES_BLOQUES  |     18 |      1 |      6 |00:00:00.01 |      18 |      0 |
         0 |       |       |          |         |
     
    |* 22 |    INDEX UNIQUE SCAN                 | PK_AVANCE_BLOQUE      |   1107 |      1 |      3 |00:00:00.01 |    1411 |      0 |
         0 |       |       |          |         |
     
    ----------------------------------------------------------------------------------------------------------------------------------

  19. #19
    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
    Cela commence mal : déjà à la première opération qui est l’accès à la table ARTICULOS_ALMACEN il y a une grande différence entre le nombre des enregistrements estimées 396 et celle réelles 12381. Généralement cela est du soit à des statistiques obsolètes soit à des distributions non homogène des valeurs pour les colonnes qui constituent des filtres. Vérifiez les statistiques et la présence des histogrammes pour les colonnes en question selon le cas.
    Les autres partie parties du plan d’exécution : accès et filtres sont également très importante vous devez les poster pour faciliter l’analyse.

  20. #20
    Expert éminent
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Points : 6 446
    Points
    6 446
    Billets dans le blog
    1
    Par défaut
    Oui, c'était bien:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select * from table(dbms_xplan.display_cursor('','','allstats last'));
    J'avais oublié un bout

    On voit que l'optimiseur estime 396 lignes venant de
    ARTICULOS_ALMACEN alors qu'en réalité il y en a 12381. Ce qui l'amène à faire un NESTED LOOP qui n'est peut-être pas judicieux: on va voir 12381 les autres tables (colonnes Start).
    Je crois que l'estimation de cette cardinalité est à l'origine du mauvais plan.

    Idées pour corriger:
    - dynamic_sampling
    - extended statistics
    - SQL profiles
    - hints

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 3 123 DernièreDernière

Discussions similaires

  1. Réponses: 10
    Dernier message: 10/07/2012, 20h47
  2. Plans d'exécutions différents suivant la source
    Par jmerigea dans le forum Administration
    Réponses: 11
    Dernier message: 10/07/2009, 21h41
  3. SQL 2005 - Même requête - différent plan d'exécution
    Par Philippe Robert dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 20/06/2008, 14h50
  4. Réponses: 11
    Dernier message: 28/04/2008, 16h29
  5. Réponses: 8
    Dernier message: 11/03/2006, 18h40

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