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

Oracle Discussion :

[index] performance sur une recherche descendante


Sujet :

Oracle

  1. #1
    Membre averti

    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    379
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 379
    Points : 376
    Points
    376
    Par défaut [index] performance sur une recherche descendante
    bonjours à toutes et tous,

    sur une table de plus de cent (107 pour être exact en ce moment) millions d'enregistrements composée pour l'essentiel de: numero number(4), article number(10), groupe number(2), infos number(10), ...

    je fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    select 
      numero, groupe, sum(infos)
    from matable 
    where numero between 10 and 20 and article = 100
    group by numero, groupe
    réponse instantanée, normal, j'ai un index sur numero, article et groupe

    mais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    select 
      t.numero, t.groupe, sum(t.infos)
    from matable t
    where t.numero = ( select max( t2.numero ) from matable t2
                       where t2.numero  < t.numero
                         and t2.article = t.article
                     )
      and t.article = 100
    group by t.numero, t.groupe
    là, il faut bien 1 à 3 secondes pour obtenir la réponse. le premier réflèxe que j'ai eu et de créer un index: blabla( "numero" desc, article )
    en me disant comme je cherche en fait le total précédent (donc en descendant) cela devrait booster la chose, mais non.

    il faut savoir que la table (environ 7 gigas) et dans un tablespace dédié et les index dans un autre tablespace.

    donc, je me plante dans mes index, puisque lorsque je cherche à faire la somme sur un "numero" précis j'ai je résultat instantanément (si si!) et lorsque je recherche le numéro qui précéde le numero en cours "select max(numero)... where numero < numero and article = 100" là, c'est très long (1 à 2 secondes, rigolez pas!)

    la question est donc quel index créer pour que la recherche "arrière" donne un résultat plus rapide à ce type de requête?

    merci de votre aide.

  2. #2
    Membre expert
    Avatar de LeoAnderson
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 2 938
    Points : 3 199
    Points
    3 199
    Par défaut
    Et d'après l'explain plan, où est-ce qu'il "perd" du temps ?
    (quelles sont les opérations les plus couteuses ?)

  3. #3
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 073
    Points
    19 073
    Par défaut
    1 à 3 s pour une requête dans une table de 7Go, je trouve ça plutôt correct moi

    elle sert à quoi cette clause :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    where t2.numero  < t.numero

  4. #4
    Expert Oracle confirmé

    Homme Profil pro
    Consultant Big Data
    Inscrit en
    Mars 2003
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Consultant Big Data
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2003
    Messages : 448
    Points : 926
    Points
    926
    Par défaut
    Bonjour,

    Je suis d'accord avec Coucoucestmoi (il faudrait avoir les plans d'exécution) et Orafrance (le temps est plutôt acceptable).

    Cependant, pour essayer de t'apporter une aide, j'essairais la chose suivante.

    Tu dis avoir l'index composite sur numero, article et groupe. De plus, la création d'un autre index sur numero desc et article n'a rien donné.

    Pour moi, c'est l'ordre des colonnes de l'index qui est important. Aussi j'essairai de créer un index sur les 2 colonnes article et numéro, et dans cet ordre.

    Ainsi, je m'attends à 2 choses :
    1 ) pour la requête principale, on aurait un Range Scan de l'article (à condition que ce critère soit sélectif), car on tape sur l'article 100, et on a ensuite tous les numéros,

    2 ) pour la requête imbriquée (celle qui recherche le n° précédent), on devrait aussi avoir un Range Scan descendant avec un arrêt sur le 1er n° cherché.

    Peux-tu essayer STP et me donner le résultat ???

  5. #5
    Membre averti

    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    379
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 379
    Points : 376
    Points
    376
    Par défaut
    ouf..., pour orafrance, "where t2.numero < t.numero" me permet en fait de trouver l'enregistrement précédent pour y effectuer une somme de tous les enregistrements du même numéro, sinon, je somme tous les enregistrements situés avant le numéro jusqu'au début ce que je ne veux pas, puisque ce que je cherche c'est de calculer une évolution.

    pour le plan d'exécution, cela vole trop haut pour moi je vous le livre en espérant que je n'est pas fait à rebour...
    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
    82
     
    -----------------------------------------------------------------------------------------------------------------
    | Id  | Operation                          | Name                       | Rows  | Bytes | Cost (%CPU)| Time     |
    -----------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                   |                            |   909 |    99K|    63   (5)| 00:00:01 |
    |   1 |  TABLE ACCESS BY INDEX ROWID       | LIBCIRCUITS                |     1 |    14 |     1   (0)| 00:00:01 |
    |*  2 |   INDEX UNIQUE SCAN                | LIBCIRCUITS_1000           |     1 |       |     0   (0)| 00:00:01 |
    |   3 |   SORT ORDER BY                    |                            |   909 |    99K|    63   (5)| 00:00:01 |
    |   4 |    VIEW                            |                            |   909 |    99K|    62   (4)| 00:00:01 |
    |   5 |     UNION-ALL                      |                            |       |       |            |          |
    |*  6 |      HASH JOIN RIGHT OUTER         |                            |   874 |   122K|    25   (0)| 00:00:01 |
    |   7 |       VIEW                         |                            |    11 |  1001 |    18   (0)| 00:00:01 |
    |   8 |        SORT GROUP BY               |                            |    11 |   308 |    18   (0)| 00:00:01 |
    |   9 |         TABLE ACCESS BY INDEX ROWID| STAT_CAB_WEEK              |    51 |  1428 |    18   (0)| 00:00:01 |
    |* 10 |          INDEX SKIP SCAN           | STAT_CAB_WEEK_IDCIRCUIT    |    51 |       |    15   (0)| 00:00:01 |
    |  11 |       VIEW                         |                            |   874 | 45448 |     7   (0)| 00:00:01 |
    |* 12 |        FILTER                      |                            |       |       |            |          |
    |  13 |         MERGE JOIN OUTER           |                            |   874 | 13984 |     7   (0)| 00:00:01 |
    |* 14 |          INDEX RANGE SCAN          | LIBCIRCUITS_1000           |     6 |    18 |     1   (0)| 00:00:01 |
    |  15 |          BUFFER SORT               |                            |   156 |  2028 |     6   (0)| 00:00:01 |
    |  16 |           VIEW                     |                            |   156 |  2028 |     1   (0)| 00:00:01 |
    |  17 |            INDEX FULL SCAN         | PERIODES_WEEK_1000         |   156 |   624 |     1   (0)| 00:00:01 |
    |* 18 |      HASH JOIN OUTER               |                            |    31 |  1023 |    18   (6)| 00:00:01 |
    |* 19 |       INDEX RANGE SCAN             | PERIODES_DAY_1000          |    31 |   372 |     2   (0)| 00:00:01 |
    |  20 |       TABLE ACCESS BY INDEX ROWID  | STAT_CAB_DAY               |    17 |   357 |    15   (0)| 00:00:01 |
    |* 21 |        INDEX SKIP SCAN             | STAT_CAB_DAY_NUMWEEK_IDART |    17 |       |    14   (0)| 00:00:01 |
    |* 22 |      HASH JOIN OUTER               |                            |     4 |   328 |    19   (0)| 00:00:01 |
    |* 23 |       INDEX RANGE SCAN             | PERIODES_WEEK_1000         |     4 |    16 |     1   (0)| 00:00:01 |
    |  24 |       VIEW                         |                            |     5 |   390 |    18   (0)| 00:00:01 |
    |  25 |        SORT GROUP BY               |                            |     5 |   140 |    18   (0)| 00:00:01 |
    |  26 |         TABLE ACCESS BY INDEX ROWID| STAT_CAB_WEEK              |    51 |  1428 |    18   (0)| 00:00:01 |
    |* 27 |          INDEX SKIP SCAN           | STAT_CAB_WEEK_IDCIRCUIT    |    51 |       |    15   (0)| 00:00:01 |
    -----------------------------------------------------------------------------------------------------------------
     
    Predicate Information (identified by operation id):
    ---------------------------------------------------
     
       2 - access("ID"=:B1)
       6 - access("R"."IDCIRCUIT"(+)="C"."ID" AND "R"."NUMWEEK"(+)="P"."NUMWEEK")
      10 - access("S"."NUMWEEK">=401 AND "S"."IDART"=83149 AND "S"."IDCIRCUIT">=1 AND "S"."NUMWEEK"<=405 AND
                  "S"."IDCIRCUIT"<=4)
           filter("S"."IDART"=83149 AND "S"."NUMWEEK"<=405 AND "S"."IDCIRCUIT"<=4 AND "S"."IDCIRCUIT">=1 AND
                  "S"."NUMWEEK">=401 AND SYS_OP_DESCEND("S"."NUMWEEK")<=HEXTORAW('3DFAFDFF')  AND
                  SYS_OP_DESCEND("S"."NUMWEEK")>=HEXTORAW('3DFAF9FF') )
      12 - filter("P"."NUMWEEK">=401 AND "P"."NUMWEEK"<=405)
      14 - access("C"."ID">=1 AND "C"."ID"<=4)
      18 - access("S"."DTE"(+)="P"."DTE" AND "S"."NUMWEEK"(+)="P"."NUMWEEK")
      19 - access("P"."NUMWEEK">=401 AND "P"."NUMWEEK"<=405)
      21 - access("S"."NUMWEEK"(+)>=401 AND "S"."IDART"(+)=83149 AND "S"."NUMWEEK"(+)<=405)
           filter("S"."IDART"(+)=83149)
      22 - access("R"."NUMWEEK"(+)="P"."NUMWEEK")
      23 - access("P"."NUMWEEK">=401 AND "P"."NUMWEEK"<=405)
      27 - access("S"."NUMWEEK">=401 AND "S"."IDART"=83149 AND "S"."IDCIRCUIT">=1 AND "S"."NUMWEEK"<=405 AND
                  "S"."IDCIRCUIT"<=4)
           filter("S"."IDART"=83149 AND "S"."NUMWEEK"<=405 AND "S"."IDCIRCUIT"<=4 AND "S"."IDCIRCUIT">=1 AND
                  "S"."NUMWEEK">=401 AND SYS_OP_DESCEND("S"."NUMWEEK")<=HEXTORAW('3DFAFDFF')  AND
                  SYS_OP_DESCEND("S"."NUMWEEK")>=HEXTORAW('3DFAF9FF') )
    Elapsed: 00:00:00.03
     
    Execution Plan
    ----------------------------------------------------------
       0    SELECT STATEMENT Optimizer=ALL_ROWS (Cost=24 Card=8168 Bytes
            =16336)
     
       1   0  COLLECTION ITERATOR (PICKLER FETCH) OF 'DISPLAY'
     
     
     
     
    Statistics
    ----------------------------------------------------------
             47  recursive calls
              0  db block gets
             16  consistent gets
              3  physical reads
              0  redo size
           6111  bytes sent via SQL*Net to client
            541  bytes received via SQL*Net from client
              5  SQL*Net roundtrips to/from client
              1  sorts (memory)
              0  sorts (disk)
             58  rows processed
    bien sur, la requête présentée dans ma demande est juste un extrait simplifié, mais en prenant juste cette partie de la requête, j'ai des réponses "lentes"

    le "plan" ci-dessus pour autant que cela soit effectivement cela représente le résultat de la totalité de la requete sur 5 périodes.

    en fonctionnement, j'obtient une réponse "instantanée" lorsque tous les "numweek" (numero dans l'exemple simplifié) sont contiguë, mais prend quelques secondes lorsqu'il y a des trous, pour faire con: 1,2,3,4,5 ==> banzai; 1 3 4 5 6 ==> lent.

    ayant testés chaque (sous)select indépendament lors de la construction du bigniou, j'ai forcément loacalisé le select qui ralenti, c'est celui qui cherche à retrouver les éléments "numweek" précédents ("where t2.numero < t.numero")

    je pense tester des index séparer, un champ par index, plutôt qu'un ou des composés, mais je ne suis pas sûr que cela apporte quelque chose?

    en fait, je suis très étonné des performances de ces tests et je ne cormprend pas pourquoi une somme sur une periode (numweek dans le plan ou numero dans l'exemple soumis) est instantanée et que la même somme sur la période précédente (where t2.numero < t.numero) prend aussi longtemps.

    pour orafrance voici la sous requête qui somme les élements de la précédente période
    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
     
    /../
          CASE WHEN R.Cumul_Infos IS NULL
              THEN ( SELECT SUM( X.Cumul_QTREdress ) FROM STAT_CAB_WEEK X
                      WHERE X.NumWeek = ( SELECT Max( NumWeek ) FROM STAT_CAB_WEEK
                                          WHERE NumWeek < P.NumWeek
                                            AND IDArt   = X.IDArt
                                        )
                        AND X.IDArt     = 83149
                        AND X.IDCircuit = C.ID
                    )
     
            ELSE R.Cumul_Infos
          END                           AS Cumul_Infos
     
    /../
    en gros, lorsque le cumul n'existe pas (période absente, d'où "R.Cumul_Infos IS NULL") je recherche la dernière période précédant la période en cours, puis j'en fait la somme.

    le test à bien sûr était fait "que" sur cette requête en y mettant les infos nécessaires à sa bonne exécution!

    evidement, j'ai probablement programmé cela avec le pied gauche ce qui expliquerai cela...

  6. #6
    Membre expert
    Avatar de LeoAnderson
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 2 938
    Points : 3 199
    Points
    3 199
    Par défaut
    Ben là, ça va pas être facile : vous nous donnez le code de la requête simplifiée mais lente et l'explain plan de la requête compliquée !

    L'idéal serait que vous puissiez nous communiquer :
    • La requête lente exacte (avec les vrais noms de tables, les vrais paramètres, ...)
      Le plan d'exécution de cette requête pré-citée


    Ceci étant, je suis d'accord sur le fait que 3 secondes pour 7 Go, c'est pas mal comme résultats...
    il doit être over-clocké votre Pentium 75 MHz pour répondre aussi vite !

  7. #7
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 073
    Points
    19 073
    Par défaut
    en utilisant les fonctions analytiques LEAD et MAX il y aurait peut-être possibilité de faire mieux, mais encore une fois 3s c'est très correct... quel temps recherche-tu ?

    http://lalystar.developpez.com/fonctionsAnalytiques/

  8. #8
    Membre averti

    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    379
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 379
    Points : 376
    Points
    376
    Par défaut
    yo! merci pour votre intérêt! et voici donc la requête dans son intégralité...

    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
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
     
    SELECT
      R.TypeInfo,
      R.NumWeek,
      R.DepuisLe,
      R.JusquAu,
     
      COALESCE( R.Infos      , 0 ) AS Infos      ,
      COALESCE( R.Cumul_Infos, 0 ) AS Cumul_Infos,
      COALESCE( R.Prior_Infos, 0 ) AS Prior_Infos,
     
     
      -- Libelle: Libellé du circuit ou du jour
      -----------------------------------------------------------------------------------------
      CASE R.TypeInfo WHEN 1 THEN ( SELECT Libelle FROM LibCircuits WHERE ID = R.IDCircuit )
                      WHEN 2 THEN CASE R.DepuisLe - NumWeek2Dates( R.NumWeek, 0 )
                                      WHEN 0 THEN 'Lundi'
                                      WHEN 1 THEN 'Mardi'
                                      WHEN 2 THEN 'Mercredi'
                                      WHEN 3 THEN 'Jeudi'
                                      WHEN 4 THEN 'Vendredi'
                                      WHEN 5 THEN 'Samedi'
                                      WHEN 6 THEN 'Dimanche'
                                    END
                      WHEN 3 THEN 'TOTAUX'
      END  AS Libelle,
     
     
      -- Evolution_Week: Calcul de l'évolution par rapport à la semaine précédente en %
      -----------------------------------------------------------------------------------------
      CASE WHEN R.TypeInfo IN ( 1, 3 )
           THEN CASE WHEN ( R.Prior_Infos = 0 ) OR ( R.Prior_Infos IS NULL )
                     THEN 0
                  ELSE ROUND( ( R.Infos - R.Prior_Infos ) * 100 / R.Prior_Infos, 2 )
                END
      END  AS Evolution_Week,
     
     
      -- DN de l'article
      -----------------------------------------------------------------------------------------
      CASE WHEN R.TypeInfo IN ( 1, 3 )
           THEN CASE WHEN ( R.MagCount = 0 ) OR ( R.MagCount IS NULL )
                     THEN 0
                  ELSE ROUND( R.DN / R.MagCount * 100, 2 )
                END
      END  AS DN
     
    FROM
    (
     
      SELECT
        1                             AS TypeInfo   ,
        R.NumWeek                                   ,
        R.IDCircuit                   AS IDCircuit  ,
        NumWeek2Dates( R.NumWeek, 0 ) AS DepuisLe   ,
        NumWeek2Dates( R.NumWeek, 1 ) AS JusquAu    ,
        R.Infos                                     ,
        COALESCE( R.Cumul_Infos, 0 ) AS Cumul_Infos ,
        COALESCE( R.Prior_Infos, 0 ) AS Prior_Infos ,
        R.DN                                        ,
        R.MagCount
      FROM
      (
        SELECT
          P.NumWeek                                   ,
          C.ID                          AS IDCircuit  ,
          COALESCE( R.Infos   , 0 )     AS Infos      ,
          COALESCE( R.DN      , 0 )     AS DN         ,
          COALESCE( R.MagCount, 0 )     AS MagCount   ,
     
          CASE WHEN R.Prior_Infos IS NULL
              THEN ( SELECT SUM( X.QTRedress ) FROM STAT_CAB_WEEK X
                      WHERE X.NumWeek   = NumWeek2PriorWeek( P.NumWeek )
                        AND X.IDArt     = 83149
                        AND X.IDCircuit = C.ID
                    )
     
            ELSE R.Prior_Infos
          END                           AS Prior_Infos,
     
     
          CASE WHEN R.Cumul_Infos IS NULL
              THEN ( SELECT SUM( X.Cumul_QTREdress ) FROM STAT_CAB_WEEK X
                      WHERE X.NumWeek = ( SELECT Max( NumWeek ) FROM STAT_CAB_WEEK
                                          WHERE NumWeek < P.NumWeek
                                            AND IDArt   = X.IDArt
                                        )
                        AND X.IDArt     = 83149
                        AND X.IDCircuit = C.ID
                    )
     
            ELSE R.Cumul_Infos
          END                           AS Cumul_Infos
     
        FROM LibCircuits C
        LEFT JOIN Periodes_Week P ON 1 = 1 -- <-- ce n'est pas une erreur!
        LEFT JOIN
        (
          SELECT
            S.NumWeek                                   ,
            S.IDCircuit                                 ,
            SUM( S.QTRedress )            AS Infos      ,
            SUM( S.Cumul_QTRedress )      AS Cumul_Infos,
            SUM( S.Prior_QTRedress )      AS Prior_Infos,
            SUM( S.DN )                   AS DN         ,
            SUM( S.MagCount )             AS MagCount
          FROM Stat_CAB_Week S
          WHERE S.IDArt = 83149
          GROUP BY S.NumWeek, S.IDCircuit
        ) R ON R.NumWeek = P.NumWeek AND R.IDCircuit = C.ID
        WHERE C.ID BETWEEN 1 AND 4
     
      ) R
     
     
      UNION ALL
     
      SELECT
        2                             AS TypeInfo   ,
        P.NumWeek                     AS NumWeek    ,
        NULL                          AS IDCircuit  ,
        P.DTE                         AS DepuisLe   ,
        P.DTE                         AS JusquAu    ,
        S.PC                          AS Infos      ,
        NULL                          AS Cumul_Infos,
        NULL                          AS Prior_Infos,
        NULL                          AS DN         ,
        NULL                          AS MagCount
      FROM Periodes_Day P
      LEFT JOIN Stat_CAB_Day S ON S.NumWeek = P.NumWeek AND S.DTE = P.DTE AND S.IDArt = 83149
     
     
      UNION ALL
     
     
      SELECT
        3                            AS TypeInfo    ,
        R.NumWeek                                   ,
        NULL                          AS IDCircuit  ,
        NumWeek2Dates( R.NumWeek, 0 ) AS DepuisLe   ,
        NumWeek2Dates( R.NumWeek, 1 ) AS JusquAu    ,
        R.Infos                                     ,
        COALESCE( R.Cumul_Infos, 0 ) AS Cumul_Infos ,
        COALESCE( R.Prior_Infos, 0 ) AS Prior_Infos ,
        R.DN                                        ,
        R.MagCount
      FROM
      (
        SELECT
          P.NumWeek                                   ,
          COALESCE( R.Infos   , 0 )     AS Infos      ,
          COALESCE( R.DN      , 0 )     AS DN         ,
          COALESCE( R.MagCount, 0 )     AS MagCount   ,
     
     
          CASE WHEN R.Prior_Infos IS NULL
              THEN ( SELECT SUM( X.QTRedress ) FROM STAT_CAB_WEEK X
                      WHERE X.NumWeek = NumWeek2PriorWeek( P.NumWeek ) AND X.IDArt = 83149
                    )
     
            ELSE R.Prior_Infos
          END                           AS Prior_Infos,
     
     
          CASE WHEN R.Cumul_Infos IS NULL
              THEN ( SELECT SUM( X.Cumul_QTREdress ) FROM STAT_CAB_WEEK X
                      WHERE X.NumWeek = ( SELECT Max( NumWeek ) FROM STAT_CAB_WEEK
                                          WHERE NumWeek < P.NumWeek
                                            AND IDArt   = X.IDArt
                                        )
                        AND X.IDArt = 83149
                    )
     
            ELSE R.Cumul_Infos
          END                           AS Cumul_Infos
     
     
        FROM Periodes_Week P
        LEFT JOIN
        (
          SELECT
            S.NumWeek                                 ,
            SUM( S.QTRedress )          AS Infos      ,
            SUM( S.Cumul_QTRedress )    AS Cumul_Infos,
            SUM( S.Prior_QTRedress )    AS Prior_Infos,
            SUM( S.DN )                 AS DN         ,
            SUM( S.MagCount )           AS MagCount
          FROM Stat_CAB_Week S
          WHERE S.IDCircuit BETWEEN 1 AND 4
            AND S.IDArt = 83149
          GROUP BY S.NumWeek
        ) R ON R.NumWeek = P.NumWeek
     
      ) R
     
    ) R
    WHERE R.NumWeek BETWEEN 401 AND 405
    ORDER BY R.NumWeek, R.TypeInfo, R.IDCircuit, R.DepuisLe
    mais pas la peine de tourner autour, c'est la partie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
          CASE WHEN R.Cumul_Infos IS NULL
              THEN ( SELECT SUM( X.Cumul_QTREdress ) FROM STAT_CAB_WEEK X
                      WHERE X.NumWeek = ( SELECT Max( NumWeek ) FROM STAT_CAB_WEEK
                                          WHERE NumWeek < P.NumWeek
                                            AND IDArt   = X.IDArt
                                        )
                        AND X.IDArt     = 83149
                        AND X.IDCircuit = C.ID
                    )
     
            ELSE R.Cumul_Infos
          END                           AS Cumul_Infos
    et plus spécialement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    SELECT Max( NumWeek ) FROM STAT_CAB_WEEK
                                          WHERE NumWeek < P.NumWeek
                                            AND IDArt   = X.IDArt
    qui pédale dans la choucroute...

    le reste retourne une réponse instantanée. j'ai bien sur procédés aux tests de type "NT" (Néandertale Technologie) qui consiste à remplacer le "WHERE NumWeek < P.NumWeek" par "WHERE NumWeek = P.NumWeek" et là, bingo, ensuite
    "WHERE NumWeek < P.NumWeek" par "WHERE NumWeek = P.NumWeek - 1" et rebingo, réponse instantanée.

    en outre, cette requête, je ne l'ai pas pondu comme cela, c'est en fait 3 requêtes imbriquées l'une dans l'autre (suivez le "typeinfo") et j'ai donc procédé à des optimisations query par query, table par table, mais faute de temps j'ai du zapper celle qui effectue la somme de la période précédente lorsque la période en cours et absente (d'où le test: "case when r.cumul_infos is null" )

    les périodes (numweek) est une valeur construite sur 4 chiffres à partir de l'année et du numéro de semaine suivant la norme iso-8601 (fonction que j'ai du faire) et de l'année, par exemple, 2004 et représenté par 53 périodes allant de 401 à 453.

    la table "libcircuits" et une table contenant 22 enregistrements, donc pas sur qu'un index change quoi que ce soit.
    la table "stat_cab_week" et la grosse table qui contient depuis hier plus de 108.000.000 d'enregistrements, elle à un index composé sur les champs: ("numweek", "idart", "idcircuit") et un autre qui était censé résoudre mon problème sur les champs: ( "numweek" desc, "idart" )
    la table "Periodes_Day" contient simplement l'énumération des périodes et contient donc maintenant 54 enregistrements: 401..453 et 501, donc là aussi, pas sûr qu'il faille un index.
    la table "Stat_CAB_Day" contient un peux moins de 40 millions d'enregistrements et elle est indexée sur les champs: "numweek" et "idart", cette table répond instanément aux requêtes.

    a noté qu'il manque l'index primaire sur stat_cab_week mais son retrait n'a rien changé, sauf pour le remplissage de cette table qui dure maintenant 2 heures au lieu de 20 minutes.

    voilà, c'est tout pour les tables et les index, il n'y a rien d'autre.

    notez que je colle cette requête dans isql*plus et quelle fonctionne tel quelle, je pense que c'est important de le dire.

    la bizarrerie des "left join" est due au fait que quelque soit la période demandée, il faut quelle retourne absolument des infos et par forcément que des 0, d'où mon problème de rechercher le précédent cumul pour le retourner avec le reste.

    à la question pourquoi faire une seule requête avec 3, simplement parce que cela est plus rapide dans le contexte utilisé, une seule question, une seule réponse et une boucle à rupture de séquence qui distribue les données.

    le temps recherché ... instantané, comme pour le reste, il n'y a à priori rien qu'il l'en enpêche, sauf mon incompétence face à oracle (je suis plus firbird...)

    le pentium 75 mhz et un p4 à 2,4Ghz avec 512M de ram et un disque de 80G ide à 7000 tours le tout piloté par un linux mandrake 10.0 customisé grâces au infos glanées sur le net et dont j'en ai fait une "main-courante" qui me permet de reinstaller le tout en moins de 2 heures debout face à la machine arrêtée et non formatée, les cds en main...

    pour le lien avec "lalystar", je connais, je lui est d'ailleurs transmis avant les fêtes le script de la procédure stockée (qui est obsolet maintenant, car il manque justement ces tables) qui charge toutes les tables du système de calcul.

    bon, j'arrête la pour l'instant...

    bien à vous...

  9. #9
    Membre expert
    Avatar de LeoAnderson
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 2 938
    Points : 3 199
    Points
    3 199
    Par défaut
    Concrètement, quel temps met :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    SELECT SUM(X.Cumul_QTREdress)
      FROM STAT_CAB_WEEK X
     WHERE X.NumWeek = (SELECT Max(NumWeek)
                          FROM STAT_CAB_WEEK
                         WHERE NumWeek < P.NumWeek
                           AND IDArt = X.IDArt)
       AND X.IDArt = 83149
       AND X.IDCircuit = C.ID;
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT Max(NumWeek)
      FROM STAT_CAB_WEEK
     WHERE NumWeek < P.NumWeek
       AND IDArt = X.IDArt;
    Sinon, au lieu de faire un index "NumWeek Desc, IDArt", que donne "NumWeek, IDArt" ?
    Et stockez-vous beaucoup d'historiques de NumWeek ? ou juste l'année en
    cours ?

    Mais bon, vu la tête de la requête, 3 secondes.... c'est bien !
    (et son explain plan est plutôt bon... )

  10. #10
    Membre averti

    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    379
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 379
    Points : 376
    Points
    376
    Par défaut
    une bonne seconde toute seule et environ 3/5 secondes lorsqu'elle est "actionnée" dans le tas sur 5 périodes.

    pour le reste, lorsque des données existent sur la ou les périodes demandées (donc cette requête n'est pas utilisée, grâce à la programmation dans le case) la réponse du "bazar" et instantanée!

    actuellement j'ai une année (2004) soit (il y a une heure environ plus de 109 millions d'enregistrements) mais à terme, je penche pour un historique de 3 ans.

    c'est pour cela que je cherche à déterminer le pourquoi du comment avant que cela ne deviennent ingérable, surtout que de surcroit, je pense à un problème que j'ai sous le nez et que je ne vois pas! c'est l'origine de ma demande

    j'ai vu un topic ici même sur des index fractionnés, c'est peux-être une piste à défaut d'avoir une solution net et franche sur l'ajout ou la modification d'un des index existants?

  11. #11
    Membre expert

    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Janvier 2004
    Messages
    2 862
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 862
    Points : 3 609
    Points
    3 609
    Par défaut
    Pourquoi ne pas faire une requête avec les fonctions analytiques comme vous l'a conseillé orafrance? Celles-ci me semble particulièrement adaptées à votre problème.
    Un problème sans solution est un problème mal posé

    Merci de poser vos questions sur le forum, je ne réponds pas aux questions posées par MP.

  12. #12
    Membre expert
    Avatar de LeoAnderson
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 2 938
    Points : 3 199
    Points
    3 199
    Par défaut
    Je ne suis suis pas sûr du tout qu'il y ait un problème, puisque le principe du "je récupères les valeurs là où xxx est maximal" est assez couteux en traitement numériques (puisqu'il faut tout parcourir 2 fois, grosso-modo)...
    Et à ma connaissance, Oracle ne sait pas faire de l'analogique !

    Et sinon, éventuellement qu'on pourrait penser à partitionner l'index sur NumWeek mais si vous avez 150 NumWeeks distincts, ça fait 150 partitions distinctes, et à mon avis, à gérer, c'est peut-être pas évident... (d'où ma question sur l'historique des NumWeek... ;-) )
    Si le temps de 3 secondes est réellement inacceptable, vous pouvez essayer cette solution...

  13. #13
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 073
    Points
    19 073
    Par défaut
    Citation Envoyé par coucoucestmoi
    Je ne suis suis pas sûr du tout qu'il y ait un problème, puisque le principe du "je récupères les valeurs là où xxx est maximal" est assez couteux en traitement numériques (puisqu'il faut tout parcourir 2 fois, grosso-modo)...
    Et à ma connaissance, Oracle ne sait pas faire de l'analogique !
    sauf que les fonctions analytiques permettent de traiter ce qu'il y a en mémoire et j'imagine qu'Oracle a fait en sorte que ce soit plus performant... mais bon, c'est vraiment pour le fun parce que je suis pas certain que ce soit très utile

  14. #14
    Membre expert
    Avatar de LeoAnderson
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 2 938
    Points : 3 199
    Points
    3 199
    Par défaut
    Désolé, je dois être fatigué, mais je comprend pas le sens de tes propos ?!

  15. #15
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 073
    Points
    19 073
    Par défaut
    simplement qu'Oracle aura surement fait le nécessaire pour pas avoir 2 passes à faire ou de le faire plus intelligemment avec les fonctions analytiques

  16. #16
    Membre expert
    Avatar de LeoAnderson
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 2 938
    Points : 3 199
    Points
    3 199
    Par défaut
    A mon avis, c'est un peu le même problème que de connaitre le poids du plus grand spaghetti dans un sachet (qui a été mal mené et tous les spaghettis n'ont pas la même taille).

    Soit, on les mesurer un par un, on note le plus grand, et ensuite, on les reprend pour retrouver le plus grand (si on est intelligent, on fait des sous-groupes, mais bon, le principe est le même) et alors là, on le pèse.

    Soit on les rassemble en tas dans la main et on tapote le paquet ainsi obtenu. Celui qui dépasse, c'est le plus grand et on le pèse !

    Or, la 2nde méthode ne peut pas être facilement implantée sur n'importe quelle architecture matérielle je crains !

  17. #17
    Membre averti

    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    379
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 379
    Points : 376
    Points
    376
    Par défaut
    le problème est résolu!

    de fait, j'avais bien le nez écrasé sur le problème et je ne le voyais pas!

    explication: lorsqu'une période n'existe pas, il me faut retrouver le dernier cumul existant avant cette période et sommer les cumuls par circuit. pour ce faire, j'utilise la requête "select max(..." qui me retourne la dernière période disponible avant celle que l'on demande (l'historique) et c'est là qu'il y avait des délais d'attentes que je trouvais inacceptables!

    la solution était évidente! en effet, il y a une égalité par IDArt et un "scan" par MAX(NumWeek) ... NumWeek < NumWeek(actuel) or comme expliqué plus haut, j'avais construit un index descendant sur NumWeek, ce qui me semblé justifié par la recherche "NumWeek < NumWeek(actuel)" suivi de l'article et c'est là l'erreur , il faut d'abord placer IDArt suivi de l'index descendant sur les périodes puisque j'ai une égalité sur l'article et pas sur la période.

    la recherche sur l'article supprime d'emblé plus de 1,3 millions de résultats (multiplié par le nombre de sous ensemble qui est ici 22, si, si, puisque je vous le dis) et reste donc les périodes et là cela devient forcément très court.

    à l'inverse (avant donc...), la recherche de l'article ne pouvait ce faire qu' après sélection d'une période, hors cette période n'était pas connue (ben oui, c'est elle que l'on cherche justement)! c'est ce qui plombé les délais, car oracle devait scanner la quasi totalité de l'index, puis seulement trouver l'égalité avec l'article...

    donc, mon index ( "NumWeek" desc, "IDArt" ) et devenu ( "IDArt", "NumWeek" desc ) et banco

    C.Q.F.D 8)

    Merci à tous pour vos avis sur la chose, j'ai encore appris beaucoup sur ce coup.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [9.2] Faibles performances d'une recherche dans un index avec GROUP BY
    Par Sebajuste dans le forum Requêtes
    Réponses: 6
    Dernier message: 12/03/2015, 18h50
  2. [SQL2K][TSQL] Trouver les indexs portant sur une colonne
    Par maitrebn dans le forum MS SQL Server
    Réponses: 9
    Dernier message: 29/08/2006, 23h09
  3. [vb6] probleme sur une recherche
    Par lumbroso dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 29/08/2006, 13h58
  4. Problème de performance sur une "grosse" BD
    Par frechy dans le forum Installation
    Réponses: 9
    Dernier message: 19/09/2005, 16h52
  5. Réponses: 8
    Dernier message: 10/09/2004, 17h30

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