Précédent   Forum des professionnels en informatique > Logiciels > Solutions d'entreprise > ERP > SAP
SAP Forum d'entraide sur SAP et sur la programmation avec le langage ABAP
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 05/04/2007, 09h31   #1
Rédacteur/Modérateur
 
Avatar de cladsam
 
Morgan Bourgeois
Inscription : août 2003
Messages : 1 730
Détails du profil
Informations personnelles :
Nom : Morgan Bourgeois
Âge : 32
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations forums :
Inscription : août 2003
Messages : 1 730
Points : 1 862
Points : 1 862
Par défaut [SD] optimisation des acces en base

Bonjour,

j'aimerais savoir si vous pourriez me conseiller sur de l'amélioration des perfs de requetes.
Le but étant de reprendre un existant dont les requetes sont non optimisées, a tel point qu'une fois en prod c'est BOOM, request time out à chaque fois.

JE vais vous mettre la premiere requete telle qu'elle était et ensuite ma première "correction" pour voir ce que vous en pensez:
Code ABAP :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  SELECT * FROM mard WHERE matnr IN s_matnr
                       AND werks IN s_werks
*                      AND spart IN s_spart
                       AND lgort IN s_lgort.
*   Initialisation de la quantité
    CLEAR wmenge.
    wmenge = mard-insme + mard-einme + mard-speme + mard-retme.

    SELECT * FROM mseg WHERE bukrs = p_bukrs
                         AND matnr = mard-matnr
                         AND werks = mard-werks
                         AND lgort = mard-lgort.

Traitement
     SELECT * FROM mkpf WHERE mblnr = mseg-mblnr
                   AND mjahr = li_mseg-mjahr
                   AND budat >= s_dtper-low.
ENDSELECT.
ENDSELECT.
ENDSELECT.

J'ai remplacé par :
Code ABAP :
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 * FROM mard
  INTO CORRESPONDING FIELDS OF TABLE li_mard
  WHERE matnr IN s_matnr
                       AND werks IN s_werks
                       AND lgort IN s_lgort.

    IF NOT li_mard[] IS INITIAL.

    SELECT *
    INTO CORRESPONDING FIELDS OF TABLE wt_mseg
    FROM mseg AS a
    INNER JOIN mkpf AS b
        ON  a~mandt = b~mandt
           AND a~mblnr = b~mblnr
          AND a~mjahr = b~mjahr
    FOR ALL ENTRIES IN li_mard
    WHERE   a~bukrs = p_bukrs
          AND a~matnr = li_mard-matnr
          AND a~werks = li_mard-werks
          AND a~lgort = li_mard-lgort
          AND b~budat >= s_dtper-low.

     ENDIF.

Je voudrais savoir ce que vous pensez de cette modif, si vous avez des conseils globaux ) me donner pour effectuer ce genre de boulot (l'optimisation), sachant qu'il reste encore une quantité importante de select disséminés dans le code.

Merci de votre aide
__________________
----------------------------------------------------
Consultant technico-fonctionnel SAP logistique -
Mon site sur developpez
---------------------------------------------------
Anakin Skywalker turn to the Dark Side after his failed attempt to upgrade R/2-D2 to R/3-D2.
cladsam est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/04/2007, 12h23   #2
Membre à l'essai
 
Inscription : août 2006
Messages : 40
Détails du profil
Informations forums :
Inscription : août 2006
Messages : 40
Points : 24
Points : 24
Bonjour cladsam,

Dans ce genre de requêtes, la première chose à faire est de regarder, quand la requête tourne, avec la transaction SM50, ce qui prend le plus de temps :
- accès en lecture séquentiel sur une table,
- accès répétés à la même table,

Ensuite, en fonction de celà tu peux adapter le code.

Ce que tu as fait est très bien :
  • Passer le plus possible par des tables internes, même si le nombre de données est important, c'est plus rapide de travailler sur une table interne que sur la base de données.
  • Ensuite utiliser des jointures plutôt que des select imbriqués.
  • Et enfin, je dirais de bien regarder dans les tables, l'ordre des clés, ainsi que les index à disposition pour que les select puissent les utiliser au maximum afin d'éviter les lectures séquentielles.

Enfin, si le time out est trop court, lancer ces requêtes en arrière-plan.

Très bonne journée et bon week-end de Pâques.
Frooty
Frooty est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/04/2007, 13h27   #3
Rédacteur/Modérateur
 
Avatar de cladsam
 
Morgan Bourgeois
Inscription : août 2003
Messages : 1 730
Détails du profil
Informations personnelles :
Nom : Morgan Bourgeois
Âge : 32
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations forums :
Inscription : août 2003
Messages : 1 730
Points : 1 862
Points : 1 862
Et bien c'est clair dans mon cas après quelques analyse, c'est les accès séquentiels ) MSEG qui prennent le plus soit environ 65% du temps total.
Ce n'ets pas peu dire ! Sachant cela, que me conseilleriez vous ?
__________________
----------------------------------------------------
Consultant technico-fonctionnel SAP logistique -
Mon site sur developpez
---------------------------------------------------
Anakin Skywalker turn to the Dark Side after his failed attempt to upgrade R/2-D2 to R/3-D2.
cladsam est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/04/2007, 20h57   #4
Membre expérimenté

 
SAP for Banking
Inscription : juin 2002
Messages : 539
Détails du profil
Informations personnelles :
Âge : 35
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : SAP for Banking
Secteur : Conseil

Informations forums :
Inscription : juin 2002
Messages : 539
Points : 566
Points : 566
Bonjour à vous,

En fait, la méthode d'analyse d'une requête repose sur principalement deux choses SM50 pour voir si elle tourne ou non, mais surtout ST05 pour faire une SQL Trace et ainsi analyser le SQL Plan. Attention cependant à l'utilisation de la table interne (ST02) pour ne pas faire déborder le cache. Ensuite, en accord avec la base de donnée, il faut plus ou moins adapter le nombre de COMMIT/ROLLOUT et la gestion du Update Task. En sachant que l'essentiel, en production est la définition même des Index et la configuration de la base de données elle-même.

L.
__________________
TRY.
N/A
CATCH cx_root.
ludovic.fernandez est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/04/2007, 10h46   #5
Membre habitué
 
Inscription : juin 2003
Messages : 146
Détails du profil
Informations personnelles :
Âge : 31
Localisation : France, Vienne (Poitou Charente)

Informations forums :
Inscription : juin 2003
Messages : 146
Points : 135
Points : 135
Envoyer un message via MSN à Sh@m@n
Bonjour,


Pr ma part, on m'a tjrs dit que les jointure sous SAP étaient loin d'être géniale concernant les performance.

Mon chef de projet m'a expliqué qu'il est préférable, plutot que de faire des jointure, de faire :
=> des SELECT plus générale sur la BD sur les 2-3 ou X tables
=> et de travailler sur les tables internes (où en gros, on va faire comme des jointures dessus). Après, bien sur, il sagit de bien travailler, et de la bonne manière sur ces tables.

Pr ma part, j'ai pu vérifier à plusieurs reprise qu'il avait raison. Maintenant, il vrai que ton optimisation à l'air bien meilleur que l'ancienne version.
A toi de voir.

Bonne journée.
Sh@m@n est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/04/2007, 16h02   #6
Membre du Club
 
Inscription : mars 2007
Messages : 62
Détails du profil
Informations forums :
Inscription : mars 2007
Messages : 62
Points : 61
Points : 61
Bonjour. Voila les points que j'ai pu remarquer.

Citation:
Envoyé par cladsam
J'ai remplacé par :
Code ABAP :
1
2
3
4
5
6
  SELECT * FROM mard
  INTO CORRESPONDING FIELDS OF TABLE li_mard
  WHERE matnr IN s_matnr
                       AND werks IN s_werks
                       AND lgort IN s_lgort.
Si li_mard est une ligne du meme type que mard enleves "corresponding fields of". Cela ralenti la QUERY du fait qu'il doit analyser la structure.

Citation:
Envoyé par cladsam
Code ABAP :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    IF NOT li_mard[] IS INITIAL.

    SELECT *
    INTO CORRESPONDING FIELDS OF TABLE wt_mseg
    FROM mseg AS a
    INNER JOIN mkpf AS b
        ON  a~mandt = b~mandt
           AND a~mblnr = b~mblnr
          AND a~mjahr = b~mjahr
    FOR ALL ENTRIES IN li_mard
    WHERE   a~bukrs = p_bukrs
          AND a~matnr = li_mard-matnr
          AND a~werks = li_mard-werks
          AND a~lgort = li_mard-lgort
          AND b~budat >= s_dtper-low.

     ENDIF.

Je voudrais savoir ce que vous pensez de cette modif, si vous avez des conseils globaux ) me donner pour effectuer ce genre de boulot (l'optimisation), sachant qu'il reste encore une quantité importante de select disséminés dans le code.

Merci de votre aide
Autre chose le 'FOR ALL ENTRIES' est plutôt deconseiller. Je te conseille de remettre les parametres de selection comme pour la premiere requete
Code ABAP :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    IF NOT li_mard[] IS INITIAL.

    SELECT *
    INTO CORRESPONDING FIELDS OF TABLE wt_mseg
    FROM mseg AS a
    INNER JOIN mkpf AS b
        ON  a~mandt = b~mandt
           AND a~mblnr = b~mblnr
          AND a~mjahr = b~mjahr
****    FOR ALL ENTRIES IN li_mard
    WHERE   a~bukrs = p_bukrs
****         AND a~matnr = li_mard-matnr
****          AND a~werks = li_mard-werks
****          AND a~lgort = li_mard-lgort
          AND a~matnr IN  s_matnr
          AND a~werks IN s_werks
          AND a~lgort IN s_lgort
          AND b~budat >= s_dtper-low.

     ENDIF.

Bien sur tu peux aussi créer des index secondaires parfois plus adaptés que ceux par defaut.
Enlever mandt de la requete cela ne sert pas vu que l'open SQL gère les requetes dans le mandant en cours.

Une autre chose comme a dit Sh@m@n c'est parfois plus efficace d'utiliser pluseiurs requetes que de faire une jointure. Plus specialement pour les tables qui sont buffurisées. Pour savoir si une table est bufferisée SE11 -> technical data.
Blash est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/04/2007, 18h41   #7
Membre habitué
 
Inscription : septembre 2005
Messages : 164
Détails du profil
Informations forums :
Inscription : septembre 2005
Messages : 164
Points : 104
Points : 104
Je ne sais pas si c'est réalisable mais a ta place je ferai une procédure stocké ^^. Ca fait un gros gros gain sur les base de donnée habituellement.
Heptaeon est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/06/2007, 12h23   #8
Candidat au titre de Membre du Club
 
Inscription : mai 2003
Messages : 16
Détails du profil
Informations forums :
Inscription : mai 2003
Messages : 16
Points : 11
Points : 11
Salut,

on a eu le même souci au taf récemment, on a fini par faire des requêtes dans des tables internes directement comme dans ton exemple amélioré mais sans utiliser le FOR ALL ENTRIES

Une fois mes différents select fait, on utilise un loop indexé afin de réunir les différentes données des deux tables dans une troisième table, les performances ont été pas mal amélioré en prod grâce à ça...

Je te conseille aussi d'oublier les SELECT *, il faut absolument spécifier les champs que tu veux, tu passes de 200 colonnes+ à finalement une quinzaine de colonne maximum...

Exemple :
Code :
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
* Chargement des tables BKPF et BSEG
  SELECT bukrs belnr gjahr blart budat bstat
           FROM bkpf INTO TABLE tg_bkpf
           WHERE "mes critères.

  IF tg_bkpf IS INITIAL.
    EXIT.
  ENDIF.

  SELECT bukrs belnr gjahr wrbtr shkzg bschl hkont fkber fistl projk dmbtr aufnr
           FROM bseg INTO TABLE tg_bseg
           WHERE "mes critères

  vl_cpt = 1.

  " on trie les tables pour pouvoir effectuer le loop indexé
  SORT tg_bkpf BY bukrs belnr gjahr.
  SORT tg_bseg BY bukrs belnr gjahr hkont.

  LOOP AT tg_bkpf INTO sg_bkpf.
    LOOP AT tg_bseg INTO sg_bseg FROM vl_cpt.
      " si la clé de bseg est supérieure on mémorise la position
      " et on sort de la boucle afin d'itérer sur bkpf
      IF sg_bseg(18) > sg_bkpf(18).
        vl_cpt = sy-tabix.
        EXIT.
        " on a les clés identiques, on peut valoriser la table finale
      ELSEIF sg_bseg(18) = sg_bkpf(18).

        " on remplit les différents champs qu'on devra afficher
        MOVE XX TO sg_final-XX.

        " on ajoute la ligne correspondante
        APPEND sg_final TO tg_final.
      ENDIF.
    ENDLOOP.
  ENDLOOP.
En espérant que ça t'ait aider un peu
kribot est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/06/2007, 17h05   #9
Rédacteur/Modérateur
 
Avatar de cladsam
 
Morgan Bourgeois
Inscription : août 2003
Messages : 1 730
Détails du profil
Informations personnelles :
Nom : Morgan Bourgeois
Âge : 32
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations forums :
Inscription : août 2003
Messages : 1 730
Points : 1 862
Points : 1 862
Merci

et merci a tous ceux qui m'ont apporté leur aide, mon gros problème finalement ne venait pas de la ... ne fois les accès MSEG effectués je me suis aperçu que le programme allait faire 5 select pour chaque article de la table sauf que :
- le données des select était au niveau division et organisation
- tous les articles de la table interne appartenaient a la meme division
- il y avait en moyen 150 000 lignes dans la table interne a ce moment la

donc en résumé : le programme faisait 5* 150 000 selects ou 5 aurait suffit ... après on vient me parler d'optimisation , moralité , le programme en question à pris la direction de la poubelle, comme il se doit
__________________
----------------------------------------------------
Consultant technico-fonctionnel SAP logistique -
Mon site sur developpez
---------------------------------------------------
Anakin Skywalker turn to the Dark Side after his failed attempt to upgrade R/2-D2 to R/3-D2.
cladsam est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 21h21.


 
 
 
 
Partenaires

Hébergement Web