Kit de Developemment SAP 4.6

Kit de Developemment SAP 4.6

Messagede CAL_DE_TER » 15 Janvier 2010, 09:35

Bonjour, à titre d'exemple :

I. Objet du document :

Il est important d’adopter des normes de développement pour des raisons de maintenance du code, d’efficacité, de lisibilité et d’homogénéité des développements SAP à la NOM DU CLIENT.
Dans le cadre d’un projet , il est important que tous les développeurs impliqués puissent relire du code fait par une autre personne sans difficulté. Pour ce faire, une norme commune est indispensable.

II. Normer le code
A. Mettre des entêtes

Chaque programme doit avoir une entête au format :

*&*-------------------------------------------------------------------------------*&*
*&* Organisation : NOM DU CLIENT
*&* Projet :
*&* Fonctionnalité :
*&* Transaction liée :
*&* Version :
*&* Dernier n° d’ordre de transport :
*&*-------------------------------------------------------------------------------*&*
*&* HISTORIQUE
*&*-------------------------------------------------------------------------------*&*
*&*
*&*-------------------------------------------------------------------------------*&*

Explication des zones (toutes obligatoires) :

Projet : nom du projet initial pour lequel a été créé le programme
Fonctionnalité : but du programme (peut tenir sur plusieurs lignes)
Transaction liée : code transaction (s’il existe) par lequel on appelle le programme.
Version : composé de trois chiffres, le numéro de version évolue à chaque modification et est pisté dans l’historique.
Dernier n° d’ordre de transport : numéro du dernier ordre de transport correspondant à ce programme.
Historique : chaque modification est notifiée ici sous la forme suivante :
DATE – AUTEUR – NOUVELLE VERSION – ORDRE DE TRANSPORT CONCERNE – OBJET DE LA MODIFICATION
On y trouve au moins une ligne CREATION pour la version 001.
Les dernières modifications apparaissent en tête de liste.

Exemple :

*&*----------------------------------------------------------------------------------------*&*
*&* Organisation : NOM DU CLIENT
*&* Projet : SAP Immos
*&* Fonctionnalité : liste des OTP à répartir
*&* Transaction liée : ZLSTPRJ
*&* Version : 003
*&* Dernier n° d’ordre de transport : DIMK900980
*&*----------------------------------------------------------------------------------------*&*
*&* HISTORIQUE
*&*----------------------------------------------------------------------------------------*&*
*&* 01/02/2002 – A. DUPONT – 003 – DIMK900980 – Ajout contrôles d’autorisation sur la région
*&* 01/02/2002 – A. DUPONT – 002 – DIMK900978 – Ajout région sur écran de sélection
*&* 01/01/2002 – A. DUPONT – 001 – DIMK900970 – CREATION
*&*----------------------------------------------------------------------------------------*&*

Chaque sous-programme, fonction ou module doit avoir une entête au format :

*&*-------------------------------------------------------------------------------*&*
*&* FORM ……… [USING….]
*&*-------------------------------------------------------------------------------*&*
*&* Ecrire ici la fonctionnalité
*&*-------------------------------------------------------------------------------*&*
*&* Paramètres d’entrée [si USING]
*&*-------------------------------------------------------------------------------*&*
*&* CREATION LE XX/XX/XXXX
*&*-------------------------------------------------------------------------------*&*

Exemple avec paramètres :

*&*-------------------------------------------------------------------------------*&*
*&* FORM RELIRE_ANLA USING tliste
*&*-------------------------------------------------------------------------------*&*
*&* Procédure d’affichage de la liste des immobilisations
*&*-------------------------------------------------------------------------------*&*
*&* Paramètres d’entrée :
*&* tliste : table interne ayant la structure de la table ANLA
*&*-------------------------------------------------------------------------------*&*
*&* CREATION LE XX/XX/XXXX
*&*-------------------------------------------------------------------------------*&*

Exemple sans paramètre :

*&*-------------------------------------------------------------------------------*&*
*&* FORM RELIRE_ANLA.
*&*-------------------------------------------------------------------------------*&*
*&* Procédure d’affichage de la liste des immobilisations
*&*-------------------------------------------------------------------------------*&*
*&* Paramètres d’entrée : Néant
*&*-------------------------------------------------------------------------------*&*
*&* CREATION LE XX/XX/XXXX
*&*-------------------------------------------------------------------------------*&*

B. Mise en forme du code (fonctionnalités SE38 & SE80)

Il est fortement recommandé d’utiliser la fonctionnalité « Pretty Printer » afin de formater automatiquement le texte du programme (indentations automatiques et mots réservés en majuscules).

Les modèles permettent aussi d’éviter les erreurs de syntaxe d’instructions complexes (Bouton « Modèle »).

C. Structure d’un programme

ENTETE
Nom du report

DECLARATIONS :
Includes
Tables
Types
Data
Constantes

ECRAN DE SELECTION

EVENEMENTS
Initialization
Top-of-page
Top-of-page during line-selection
At line-selection
Start-of-selection
End-of-selection
At user-command
Autres évènements
Sous-programmes

D. Règles de Nommage

Select_options : so_
Parameters : p_
Table interne X : ti_X
Fields_symbols : fs _
TOP include : ZXXXXTOP
Include : ZINCXXXX
Sous-programme : RELIRE_XXX (VERBE EN PREMIER)
Data x type entier : vint_x
Data x type caractères : vcar_x
Data x type numérique : vnum_x
Data x type paquet : vpac_x
Data x type virgule flottante : vflo_x

E. Commentaires

Pour un souci de clarté, toute suite de code ABAP doit être commentée de façon claire et concise.

III. Optimisations du code

A. Conditions WHERE manquantes

Le mode de sélection et d’utilisation des index de base de données par le programme d’optimisation des accès de base de données dépend, entre autres, des conditions WHERE spécifiées dans l’instruction SQL.

La chaîne de recherche d’index est concaténée dans les zones spécifiées sans gaps (espaces) et est spécifiée par ‘=’ dans la condition WHERE.

Exemple avec la table ANLA :

Index :
MANDT
BUKRS
ANLN1
ANLN2

A noter que ces informations peuvent être aisément retrouvées par le biais de la transaction SE11.

Exemple d’utilisation inefficace de l’index :

SELECT *
FROM ANLA
INTO table ti_anla
WHERE ANLN1 = ‘4000096’.

Ecart dans la chaîne de recherche : ‘020____0004000096’
Il manque la société.

Exemple d’utilisation efficace de l’index :

SELECT *
FROM ANLA
INTO table ti_anla
WHERE BUKRS = ‘1000’
AND ANLN1 = ‘4000096’.

Zones d’index spécifiées intégralement dans la chaîne de recherche : ‘02010000004000096’

Même si tous les éléments clés de l’index ne sont pas spécifiés, il est important que la chaîne d’index ne comporte pas de « trous ». De plus, les zones de la requête doivent être ordonnées de la même façon que les champs du dictionnaire ABAP.
En reprenant l’exemple précédent et en intervertissant l’ordre des zones, la requête suivante :

SELECT *
FROM ANLA
INTO table ti_anla
WHERE ANLN1 = ‘4000096’
AND BUKRS = ‘1000’.

est moins performante.

Une utilisation incorrecte de l’option CLIENT SPECIFIED peut entraîner une utilisation inefficace de l’index de base de données. Si cette option est utilisée, une condition WHERE pour MANDT doit être présente.
N.B. : Par défaut, le mandant courant est utilisé à l’exécution de la requête par le moteur ABAP, au moment de sa traduction en SQL natif sur la base Oracle.

Exemple avec la table ANLA :

Index :
MANDT
BUKRS
ANLN1
ANLN2

Exemple d’utilisation inefficace de l’index :

SELECT *
FROM ANLA
CLIENT SPECIFIED
INTO table ti_anla
WHERE BUKRS = ‘1000’
AND ANLN1 = ‘4000096’.

Ecart dans la chaîne de recherche : ‘___10000004000096’
Il manque le mandant dans la clause WHERE.

Exemple d’utilisation efficace de l’index :

SELECT *
FROM ANLA
CLIENT SPECIFIED
Into table ti_anla
WHERE MANDT = ‘020’
AND BUKRS = ‘1000’
AND ANLN1 = ‘4000096’.

OU

SELECT *
FROM ANLA
Into table ti_anla
WHERE BUKRS = ‘1000’
AND ANLN1 = ‘4000096’.

Zones d’index spécifiées intégralement dans la chaîne de recherche : ‘02010000004000096’

B. Opérateurs critiques

Si les zones de la clause WHERE sont spécifiées avec les opérateurs NOT ou <>, ces conditions WHERE ne peuvent pas être utilisées pour une recherche dans un index base de données.
Par conséquent, il faut, dans la mesure du possible, formuler des instructions SQL de manière positive.

Si une formulation positive ne peut pas être utilisée, car la liste IN est trop longue par exemple, il faut toujours spécifier la condition WHERE sans NOT afin de réduire le volume de données à transmettre. Aucune recherche d’index n’est effectuée mais le volume est moins important.

Exemple de formulation négative :

 Utilisation inefficace des index.

SELECT ANLKL ERNAM ERDAT
Into table ti_anla
FROM ANLA
WHERE BUKRS = ‘1000’
AND not anln1 = ‘0004000096’.

Exemple de formulation positive :
 Utilisation efficace des index.

SELECT ANLKL ERNAM ERDAT
Into table ti_anla
FROM ANLA
WHERE BUKRS = ‘1000’
AND anln1 in (‘0004000090’,
‘0004000091’,
‘0004000092’,
‘0004000093’,
‘0004000094’,
‘0004000095’,
‘0004000097’).


Les opérateurs BETWEEN, LIKE, < et > ne permettent pas une bonne recherche par index, et sont très coûteux en temps et donc en performances.

C. Tri au niveau de la base de données ou dans ABAP

Pour trier le résultat d’une instruction SQL, il faut utiliser la clause ORDER BY dans la base de données ou l’instruction ABAP SORT ti_xxx dans le programme.

La base de données étant une ressource centrale ne pouvant pas être modifiée, il est recommandé d’effectuer les tris dans ABAP.
Toutefois, si un même index de base de données peut être utilisé pour le tri et la sélection des enregistrements ce données (en fonction de la clause WHERE), il est possible d’effectuer le tri dans la base de données.

Exemple de tri au niveau de la base de données avec index :

SELECT ANLKL ERNAM ERDAT
Into table ti_anla
FROM ANLA
WHERE BUKRS = ‘1000’
AND anln1 = ‘0004000096’
AND anln2 = ‘1’
ORDER BY PRIMARY KEY.

Exemple de tri au niveau de la base de données sans index :

SELECT ANLKL ERNAM ERDAT
Into table ti_anla
FROM ANLA
WHERE BUKRS = ‘1000’
AND anln1 = ‘0004000096’
AND anln2 = ‘1’
ORDER BY anlkl ASCENDING.

Exemple de tri au niveau du programme ABAP :

SELECT ANLKL ERNAM ERDAT
Into table ti_anla
FROM ANLA
WHERE BUKRS = ‘1000’
AND anln1 = ‘0004000096’
AND anln2 = ‘1’.

SORT zanla BY anlkl ASCENDING.

D. Réduction du nombre d’enregistrements à transmettre

Pour réduire le nombre d’enregistrements à transmettre, pour chaque instruction SQL, il faut spécifier une clause WHERE aussi sélective que possible. Une instruction SELECT sans condition WHERE indique une erreur de conception dans le programme.
Il faut s’assurer que le nombre d’enregistrements sélectionnés reste toujours constant, plus particulièrement lors de la sélection dans les tables de transaction (par exemple, BKPF, BSEG, COBK, COEP….)

Exemple de clause WHERE manquante :

SELECT ANLKL ERNAM ERDAT
Into table ti_anla
FROM ANLA.

Exemple de clause WHERE instable :

SELECT ANLKL ERNAM ERDAT
Into table ti_anla
FROM ANLA
WHERE anln1 in so_anln1.

Exemple de clause WHERE stable :

SELECT ANLKL ERNAM ERDAT
Into table ti_anla
FROM ANLA
WHERE BUKRS = ‘1000’
AND anln1 = ‘0004000096’
AND anln2 = ‘1’.

Pour réduire le volume de données à transmettre, ne pas formuler de conditions pour la sélection des données à l’aide d’une instruction CHECK dans SELECT…. ENDSELECT.
Il faut formuler les conditions comme faisant partie d’une clause WHERE.
IL faut toujours spécifier toutes les conditions connues dans la clause WHERE. S’il manque une condition, DBMS ne peut pas utiliser un index pour optimiser une instruction.
Afin de pouvoir réutiliser les instructions SQL et, par conséquent, utiliser de manière optimale la mémoire cache SQL BD, il faut toujours respecter l’ordre des zones spécifiées dans le dictionnaire ABAP lors de la formulation des clauses SELECT et WHERE.

Exemple de SQL avec CHECK :

SELECT ANLKL ERNAM ERDAT
FROM ANLA
Into table ti_anla.
Check BUKRS = ‘1000’
AND anln1 = ‘0004000096’
AND anln2 = ‘1’.
Append zanla to ti_anla.
ENDSELECT.

Exemple de SQL avec WHERE :

SELECT ANLKL ERNAM ERDAT
Into table ti_anla
FROM ANLA
WHERE BUKRS = ‘1000’
AND anln1 = ‘0004000096’
AND anln2 = ‘1’.
APPEND zanla to ti_anla.
ENDSELECT.
E. Réduction du nombre de colonnes à transmettre

Si SELECT * est utilisé, trop de données sont généralement transmises du serveur de base de données vers le serveur d’application. Si on souhaite accéder au contenu de quelques colonnes uniquement, il faut les spécifier dans la clause WHERE.
Si le nombre de zones peut-être réduit de plus de la moitié, la création d’une liste de zones s’avère judicieuse.
Pour obtenir plusieurs projections dans une table de base de données à différents emplacements du programme, lire toutes les zones requises en une seule fois dans la base de données, les mettre en mémoire tampon dans une table interne, puis répartir les données dans le programme.

Exemple d’erreur souvent rencontrée :

SELECT *
FROM ANLA
INTO TABLE ti_anla
WHERE BUKRS = p_bukrs.

Exemple d’instruction SQL améliorée :

SELECT anln1 anln2 anlkl
FROM ANLA
INTO CORRESPONDING FIELDS OF TABLE ti_anla
WHERE BUKRS = p_bukrs.

Exemple d’instruction SQL performante :

SELECT anln1 anln2 anlkl
FROM ANLA
INTO TABLE ti_anla
WHERE BUKRS = p_bukrs.

F. SELECT FOR ALL ENTRIES

Avec SELECT FOR ALL ENTRIES, on peut diviser les instructions SELECT en boucles. Cette variante permet de créer une jointure entre une table interne et une table de base de données.
Les instructions SELECT FOR ALL ENTRIES entraînent les problèmes suivants :
La table pilote ne peut pas être vide.
Si la table pilote est vide, la sélection n’est pas limitée. Noter que si la clause WHERE contient des conditions ne se référant pas à la table pilote interne, ces dernières ne sont pas analysées.
Les entrées de table en double doivent être supprimées de la table pilote interne avant l’exécution de SELECT FOR ALL ENTRIES. Si elles ne sont pas supprimées, des données identiques sont lues inutilement dans la base de données.

Exemple de SELECT dans un LOOP (très coûteux) :

LOOP AT ti_anla INTO zanla.
SELECT zzinsee
FROM ANLU
APPENDING TABLE ti_anlu
WHERE anln1 = zanla-anln1.
ENDLOOP.

Exemple de SELECT FOR ALL ENTRIES :

DESCRIBE TABLE ti_anla LINES lines.

IF lines = 0.
EXIT.
ENDIF.

SORT ti_anla BY anln1.

DELETE ADJACENT DUPLICATES FROM ti_anla.

SELECT zzinsee
FROM ANLU
INTO TABLE ti_anlu
FOR ALL ENTRIES IN ti_anla
WHERE anln1 = zanla-anln1.

G. Tables RANGES

On peut utiliser les tables RANGES dans ABAP. Elles sont définies avec les instructions ABAP SELECT-OTPIONS et RANGES. Ces deux instructions définissent de manière implicite une table interne contenant les zones SIGN, OPTION, LOW et HIGH.
Sur l’écran de sélection, l’utilisateur remplit de façon dynamique une table RANGES définie avec SELECT-OPTIONS. L’interface de base de données convertit les lignes d’une table RANGES de manière à ce qu’elles puissent être lues par DBMS, puis les relie avec OR. L’instruction SQL générée est alors transmise vers la base de données.

Exemple :

SELECT MANDT anln1 anln2
FROM ANLA
INTO TABLE ti_anla
WHERE BUKRS in so_bukrs.

Instruction SQL après conversion de l’interface de base de données :

SELECT « MANDT », « anln1 », « anln2 »
FROM « ANLA »
WHERE « MANDT » = :A0
AND « BUKRS » in ( :A1, :A2).

H. Fonctions d’agrégat

Pour effectuer des calculs à l’aide de DBMS, utiliser des fonctions d’agrégat (COUNT, SUM, MAX, MIN, AVG). Utiliser ces fonctions uniquement si elles réduisent de manière significative la quantité d’enregistrements de données à transmettre.
Les fonctions d’agrégat sont généralement utilisées avec une clause GROUP BY. Les instructions SQL contenant ces fonctions ignorent les tampons de tables R/3.
La base de données reconnaît la valeur NULL alors qu’ABAP ne reconnaît pas cette valeur.
Pour la fonction d’agrégat AVG, utiliser le type de données F (nombre avec virgule flottante) pour la zone cible.
Pour la fonction SUM, le type de donnée de la zone cible doit être plus long que celui de la zone source afin de permettre un dépassement.

Exemple de fonction d’agrégat dans ABAP :

SELECT BUKRS ANLN1 ANBTR
FROM ANEP
INTO TABLE ti_anep
WHERE BUKRS in so_bukrs.

LOOP AT ti_anep.
* Compte maximum de anbtr et minimum de anln1. ???
ENDLOOP

Exemple de fonction d’agrégat dans la base de données :

SELECT BUKRS Min( ANLN1 ) Max( ANBTR )
FROM ANEP
INTO TABLE ti_anep
WHERE BUKRS in so_bukrs
GROUP BY BUKRS.

I. Clause HAVING

Pour appliquer une condition logique aux groupes définis dans la clause GROUP BY, utiliser HAVING avec une instruction SELECT. La base de données détermine le volume obtenu. Le volume de données à transmettre dépend de la sélectivité de la clause HAVING.
L’utilisation des clauses HAVING est similaire à celle des fonctions d’agrégat. Les clauses HAVING créent une charge supplémentaire dans la base de données. Par conséquent, les utiliser uniquement si elles réduisent de manière significative la quantité d’enregistrements de données à transmettre. Avant d’utiliser une clause HAVING, vérifier si la condition peut être spécifiée dans la clause SELECT.

Exemple de SELECT avec CHECK :

SELECT BUKRS ANLN1 Max( ANBTR )
FROM ANEP
INTO TABLE ti_anep
WHERE BUKRS in so_bukrs
GROUP BY BUKRS.
CHECK ( ti_anep-anln1 GE g_min
AND ti_anep –anln1 LE g_max).
APPEND ti_anep to table_anep.
ENDSELECT.

Ici, tous les enregistrements de données remplissant les conditions de la clause WHERE sont lus, inutilement pour certains.

Exemple de SELECT avec HAVING :

SELECT BUKRS ANLN1 Max( ANBTR )
FROM ANEP
INTO TABLE ti_anep
WHERE BUKRS in so_bukrs
GROUP BY BUKRS
HAVING ( ti_anep-anln1 GE g_min
AND ti_anep –anln1 LE g_max).

Ici, seuls les enregistrements remplissant les conditions dans les clauses WHERE, GROUP BY et HAVING sont transmis.

J. ARRAY FETCH

Pour SELECT…ENDSELECT et ARRAY FETCH, le même nombre d’enregistrements de données doit être transmis du serveur de base de données vers le serveur d’application. Les enregistrements de données étant transmis par blocs de 32 Ko, la charge de transmission (à savoir le nombre de FETCH) est identique pour les deux variantes.
Toutefois, utiliser un ARRAY FETCH plutôt qu’une boucle SELECT…ENDSELECT, car les enregistrements de données sont transmis par enregistrement de l’interface de base de données vers le programme ABAP dans une boucle SELECT…ENDSELECT.
Dans un ARRAY FETCH, les enregistrements de données sont transmis vers le programme ABAP dans un bloc.

Exemple de SELECT…ENDSELECT :

SELECT BUKRS ANLN1
FROM ANLA
INTO ti_anla .
APPEND ti_anla.
ENDSELECT.

Exemple de ARRAY FETCH :

SELECT BUKRS ANLN1
FROM ANLA
INTO TABLE ti_anla .

K. UP TO n ROWS

Il existe deux méthodes pour lire un nombre fixe d’enregistrements de données. On peut transmettre les enregistrements de données vers le serveur d’application à l’aide de SELECT…ENDSELECT, puis déterminer si le nombre de lignes requis a été lu. Toutefois, il est préférable d’utiliser SELECT…UP TO n ROWS, car seul le nombre d’enregistrements de données demandé est transmis de la base de données vers l’application.

Exemple avec SELECT…ENDSELECT :

SELECT BUKRS ANLN1 ANLN2
FROM ANLA
INTO ti_anla
WHERE BUKRS in so_bukrs.
IF sy-dbcnt GT g_limit. EXIT. ENDIF.
APPEND ti_anla TO table_anla.
ENDSELECT.

Exemple avec SELECT…UP TO n ROWS :

SELECT BUKRS ANLN1 ANLN2
FROM ANLA
INTO TABLE ti_anla
UP TO g_limit ROWS
WHERE BUKRS in so_bukrs.

L. UPDATE…SET Zone = VALEUR

Dans une instruction UPDATE, seul le contenu de zone modifiée doit être mis à jour dans la base de données. Ces zones sont spécifiées dans UPDATE…SET zone =.
Dans la condition WHERE, on peut limiter le nombre de lignes de table à modifier.
Il est possible d’utiliser l’instruction UPDATE..SET pour plusieurs zones de la table de base de données.

Exemple de mise à jour ligne par ligne :

SELECT *
FROM ANLA
INTO ti_anla
WHERE BUKRS in so_bukrs.
Ti_anla-anln1 = ti_anla-anln1 + 5.
UPDATE ANLA FROM ti_anla.
ENDSELECT.

Exemple de mise à jour avec UPDATE…SET zone = valeur :

UPDATE ANLA
SET anln1 = anln1 + 5
WHERE BUKRS in so_bukrs.

M. Création, modification et suppression de données de masse

Pour toute modification de base de données, il est recommandé de passer par des batch-input.

N. SELECT imbriqués

L’inconvénient majeur des instructions SELECT imbriquées est leur coût en temps d’exécution et donc en performance.
Un autre inconvénient des instructions SELECT imbriquées réside dans le fait que l’ordre des accès est déterminé dans le code du programme.
Les instructions JOIN (INNER JOIN ou LEFT OUTER JOIN dans ABAP) traitées dans la base de données ne sont jamais concernées par la mise en mémoire tampon des tables R/3, contrairement aux instructions SELECT imbriquées et SELECT FOR ALL ENTRIES.

O. Utilisation des bases de données logiques

La structure d’une base de données logique détermine la hiérarchie des nœuds et, par conséquent, leur ordre de lecture. Le niveau de lecture dépend des évènements GET spécifiés dans le programme. La base de données logique lit tous les nœuds dans le chemin d’accès direct jusqu’au dernier événement GET.
Les évènements GET sont traités plusieurs fois dans le programme. Ainsi, un événement GET est similaire à un traitement de boucle. Par conséquent, la programmation d’une instruction SELECT dans un événement GET est identique à une instruction SELECT imbriquée. (cf. chapitre précédent)
L’ordre des lectures (GET) étant prédéterminé, programmer uniquement un événement GET de niveau hiérarchique inférieur seulement si les niveaux supérieurs sont également demandés.

P. Tables POOL et tables CLUSTER

AVANTAGES INCONVENIENTS
 Compression de données :
- réduction de l’espace mémoire
- réduction de la charge du réseau

 Réduction du nombre de tables et zones de tables
 Réduction du nombre d’instructions SQL différentes
 Réduction de la charge dans le dictionnaire et la mémoire tampon de la BD
 Simplification de l’administration

 Pour les tables cluster, réduction des accès à la BD.  Limites de fonctionnalités de la BD :
- aucune vue ou JOIN ABAP
- aucun index secondaire
- aucun GROUP BY, ORDRE BY…
 Aucune instruction SQL native

 Aucun ajout de tables

 Pour les tables cluster, sélection limitée des zones-clés du cluster.

 Pour les tables pool, clés plus longues que nécessaire.

Q. Tables CLUSTER

Dans les tables CLUSTER, les données dépendantes fonctionnellement réparties dans plusieurs tables sont regroupées en une table de base de données. L’intersection des zones-clés dans la table cluster forme la clé du cluster de table.

Table Cluster TABA


Table Cluster TABB

R. Accès sélectif aux tables cluster

Lors de l’accès aux tables cluster, il faut s’assurer que les clauses WHERE sont spécifiées à gauche sans gaps jusqu’à une zone sélective, car seul l’index primaire peut être utilisé.

Exemple d’instruction SQL dans ABAP :

SELECT BUKRS BELNR GJAHR KUNNR
FROM BSEG
INTO TABLE ti_bsid
WHERE BUKRS = ‘1000’
AND BELNR = ‘0000000022’.

Exemple d’instruction SQL dans la BD :

SELECT « BUKRS », « BELNR », « GJAHR », « KUNNR »,
« PAGNO », « TIMESTMP », « PAGELG », « VARDATA »
FROM « RFBLG »
WHERE « MANDT » = :A0
AND « BUKRS » = :A1
AND « BELNR » = :A2
ORDER BY « MANDT », « BUKRS », « BELNR », « GJAHR », « KUNNR », « PAGNO ».

S. Accès non sélectif aux tables cluster

Exemple d’accès non sélectif :

SELECT BUKRS BELNR GJAHR KUNNR
FROM BSEG
INTO TABLE ti_bsid
WHERE BELNR = ‘0000000022’.

Exemple d’accès sélectif :

SELECT BUKRS BELNR GJAHR KUNNR
FROM BSID
INTO TABLE ti_bsid
WHERE BELNR = ‘0000000022’.

T. Tables Pool

Un pool de tables stocke les enregistrements de données à partir de tables définies dans le dictionnaire ABAP. Ces tables ne dépendent pas les unes des autres. Les tables R/3 peu volumineuses sont regroupées pour former une table de base de données.

Table Pool TABA
Table Pool TABB

U. Accès sélectif aux tables pool

Exemple d’instruction SQL dans ABAP :

SELECT KAPPL KSCHL VKORG VTWEG MATNR
FROM AA005
INTO TABLE ti_aa005
WHERE KAPPL = ‘CS’
AND KSCHL = ‘SAPZ’
AND VKORG = ‘0001’
AND VTWEG = ‘01’
AND KUNNR = ‘00000009’
AND MATNR = ‘000000000000027’.

Exemple d’instruction SQL dans la BD :

SELECT « TABNAME » , « VARKEY » , « DATALN » , « VARDATA »
FROM « KAPOL »
WHERE « TABNAME » = :A0
AND « VARKEY » LIKE :A1
ORDER BY « TABNAME », « VARKEY ».

V. Accès non sélectif aux tables pool

Exemple d’accès non sélectif :

SELECT KAPPL KSCHL VKORG
FROM AA005
INTO TABLE ti_a0055
WHERE MATNR = ‘0000000000027’.

Traduit par l’interface de base de données en :

SELECT « TABNAME » , « VARKEY » …
FROM « KAPOL »
WHERE « TABNAME » = :A0
AND « VARKEY » LIKE :A1
ORDER BY « TABNAME »,…

Mise en mémoire tampon de l’intégralité de la table AA005 sur le serveur d’application --> lecture répétée de la base de données inutile.

Exemple d’accès sélectif :

Suppression de AA005 du pool de tables KAPOL et création d’un index pour MATNR --> lecture efficace des données possible.

W. Instructions SQL n’utilisant pas la mémoire tampon

 Instruction SQL Native
 Sous-requêtes, JOIN ABAP
 SELECT…BYPASSING BUFFER
 SELECT FOR UPDATE
 Fonctions d’agrégat (COUNT, MIN, MAX, SUM, AVG)
 SELECT DISTINCT
 Clause WHERE avec IS NULL
 ORDER BY, GROUP BY (HAVING)
 Pour les tables avec une mise en mémoire tampon par enregistrement, toutes les instructions SQL à l’exception de SELECT SINGLE
 Pour les tables avec une mise en mémoire tampon générique, toutes les instructions SQL à l’exception de SELECT *.. si la clause WHERE est zone = valeur pour toutes les zones incluses dans le domaine générique.

Mise en mémoire tampon générique :

A ne pas faire au niveau de la BASE DE DONNEES (surcharge)

SELECT * FROM TCURR
CLIENT SPECIFIED
INTO TABLE ti_tcurr
WHERE KURST = ‘EURO’.

A faire au niveau de TAMPON DE TABLE

SELECT * FROM TCURR
INTO TABLE ti_tcurr
WHERE KURST = ‘EURO’.

Mise en mémoire tampon d’enregistrements individuels :

A ne pas faire --> BASE DE DONNEES

SELECT * FROM T100
INTO TABLE ti_t100
WHERE SPRS = ‘D’
AND ARBGB = ‘BC490’
AND MSGNR = ‘050’.

A faire --> TAMPON DE TABLE

SELECT SINGLE * FROM T100
INTO TABLE ti_t100
WHERE SPRS = ‘D’
AND ARBGB = ‘BC490’
AND MSGNR = ‘050’.

X. Mise en mémoire tampon dans le programme

SELECT …
FROM VVBAK
INTO ti_vvbak
WHERE …
PERFORM READ_KNA1.
ENDSELECT.

A partir de la routine READ_KNA1 :

READ TABLE g_itab_kna1 WITH TABLE KEY KUNNR = g_wa_vvbak-kunnr.
IF sy-subrc NE 0.
SELECT SINGLE …
FROM KKNA1
INTO …
WHERE …
APPEND … TO …
ENDIF.

Y. Définition des tables internes

TYPES : BEGIN OF ti_anla,
BUKRS TYPE anla-bukrs,
Anln1 TYPE anla-anln1,
END OF ti_anla.

DATA : sort_tab TYPE SORTED TABLE OF ti_anla WITH UNIQUE KEY BUKRS [INITIAL SIZE <n>] [WITH HEADER LINE].

Désignation des tables standard :
DATA : stan_tab TYPE TABLE OF ANLA.

Utiliser l’instruction :
DATA <itab> RTYPE <tabkind> OF <linetype> [WITH[UNIQUE | NON-UNIQUE] <keydef>] [INITIAL SIZE <n>] pour créer une table interne du type <itab type> avec la catégorie de table <tabkind> en utilisant le type de ligne <linetype>.

Z. Tables internes HASHED

Utiliser une table d’adresses calculées lorsque l’on veut accéder à plusieurs enregistrements individuels dans une table intérieure via une clé primaire spécifiée intégralement.

Exemple :

LOOP AT sort_vbap INTO ti_vbap.
AT NEW ti_vbap-vbeln.
READ TABLE hash_vbak INTO ti_vbak WITH TABLE KEY
MANDT = sy-mandt VBELN = ti_vbap-vbeln.
WRITE:/ ….
ENDAT.
WRITE:/ …
ENDLOOP.

AA. Tables SORTED

Lors du traitement séquentiel partiel des tables triées, on traite des boucles optimisées (seules les lignes remplissant la condition WHERE sont traitées), à condition que la syntaxe de la condition WHERE soit la suivante : WHERE k1 = v1 AND k2 = v2 … AND kn = vn et que les composantes k1 à kn reflètent exactement le début de la clé de la table.

Exemples :

LOOP AT sort_vbpa INTO ti_vbpa
WHERE MANDT = sy-mandt
AND VBELN = ‘0000000900’.
ENDLOOP.

OU

DELETE TABLE ti_vbpa
WHERE MANDT = sy-mandt
AND VBELN = ‘0000000900’.

BB. Tables Standard

Il est recommandé d’utiliser une table standard lorsque les données auxquelles nous souhaitons accéder varient selon les différentes étapes de traitement.
Si on utilise principalement des accès via un index, une table standard est un choix judicieux, car sa contenance peut être augmentée plus rapidement que celles des deux autres types de table interne.

Exemple :

PARAMETERS : p_ernam TYPE vbak-ernam,
P_vdatu TYPE vbak-vdatu.
SORT ti_vbak BY ERNAM.
READ TABLE ti_vbak WITH KEY ERNAM = p_ernam INTO wa BINARY SEARCH.
SORT ti_vbak BY ERDAT VDATU.
LOOP AT ti_vbak INTO wa WHERE ERDAT = sy-datu AND vdatu = p_vdatu.
….
ENDLOOP.

CC. ARRAY FETCH

Il est plus performant de mémoriser les enregistrements de données en une seule fois dans la table interne au lieu de procéder enregistrement par enregistrement.

A ne pas faire -->

SELECT …
APPEND ….
ENDSELECT.

A faire -->

SELECT .. FROM .. INTO TABLE ….
LOOP AT … INTO …

ENDLOOP.

DD. Insertion de tables internes

Les instructions APPEND / INSERT LINES peuvent être utilisées pour agrandir une table interne existante. Il est également possible de copier un intervalle de lignes à partir de la table source en utilisant FROM … TO.

<itab2> = <itab1>.
APPEND LINES OF <itab1> [FROM <n1> TO <n2>] TO <itab2>.
INSERT LINES OF <itab1> [FROM <n1> TO <n2>] INTO <itab2> [INDEX <n3>].

A ne pas faire -->

LOOP AT ti_vbak2 INTO wa_vbak.
APPEND wa TO ti_vbak.
ENDLOOP.

A faire -->

APPEND LINES OF ti_vbak2 TO ti_vbak.

EE. Remplissage d’une table interne avec des valeurs cumulées

L’instruction COLLECT cumule la work area à une entrée existante identique ou insère une nouvelle entrée de table. Ceci permet de créer des tables internes agrégées et de réduire ainsi le volume de données.

L’instruction COLLECT recherche une ligne dans la table interne en fonction du type de table et de la clé définie. Si elle trouve cette ligne, elle cumule toutes les zones numériques de la work area ou de l’entête dans les zones correspondantes de la ligne de table. Si elle ne trouve pas cette ligne, elle l’ajoute en la créant à partir de la work area ou de l’entête.
Seules les zones numériques non-clés de type P, I ou F supportent l’instruction COLLECT.

Exemple :

SELECT ERNAM NETWR WAERK
FROM VBAK
INTO wa
WHERE …
COLLECT wa INTO hash_tab
ENDSELECT.

FF. Chargement des tables internes uniques

IL s’avère parfois judicieux de charger une table interne à l’aide de SELECT… INTO… de façon à ce que le nombre de zones-clés de la table interne soit inférieur à celui de la table de base de données.
Dans ce cas, la table interne peut comporter des entrées en double.
Il est possible d’utiliser l’instruction DELETE ADJACENT DUPLICATES FROM <itab> pour supprimer ces doublons.

Exemple :

SELECT * … INTO TABLE ti_vbpa.
DELETE ADJACENT DUPLICATES FROM sort_vbpa.

GG. Transfert de zones sélectives

Les instructions LOOP, READ et MODIFY placent généralement les lignes dans la work area ligne par ligne ou à partir de la work area vers la table. Les performances peuvent ainsi s’en trouver réduites.
Il est possible d’utiliser TRANSPORTING pour spécifier les zones requises ou encore TRANSPORTING NO FIELDS pour spécifier un nombre de lignes.

MODIFY … TRANSPORTING <f1> … <fn>
READ … TRANSPORTING [<f1> … <fn> | NO FIELDS]
LOOP … TRANSPORTING NO FIELDS.

HH. Utilisation des Field symbols

Les Field symbols dans ABAP sont similaires aux pointeurs dans d’autres langages de programmation tels que PASCAL ou C.

FIELD-SYMBOL <fs> [TYPE type | LIKE f].
ASSIGN <Field> TO <fs>.

II. Lecture d’enregistrements individuels

Si possible, utiliser les opérations d’index (impossible avec des tables HASHED) :

READ TABLE … INDEX

S’il est possible de spécifier intégralement la clé primaire, utiliser FROM ou WITH TABLE KEY :

READ TABLE … FROM <WA>.
READ TABLE… WITH TABLE KEY …

Utiliser BINARY SEARCH pour les tables STANDARD (après le tri) :

READ TABLE … BINARY SEARCH.

Exemple :

Wa-mandt = sy-mandt.
Wa-vbeln = ‘0000000110’.
READ TABLE ti_vbak FROM wa INTO wa.

OU

READ TABLE ti_vbak WITH TABLE KEY
MANDT = sy-mandt
VBELN = ‘0000000110’ INTO wa.

POUR LES TABLES INTERNES

SORT ti_vbak BY MANDT VBELN.
READ TABLE ti_vbak INTO wa WITH KEY
MANDT = sy-mandt
vbeln = ‘0000000110’
BINARY SEARCH.

JJ. Traitement en masse à l’aide d’une clause WHERE

A ne pas faire -->

LOOP AT … INTO …
IF…

ENDIF.
ENDLOOP.

A faire -->

LOOP AT … INTO …
WHERE ….
ENDLOOP.

KK. Traitement en masse à l’aide d’un intervalle d’index

Avec les instructions LOOP, INSERT, APPEND et DELETE, il est possible de spécifier un intervalle d’index.

Exemple :

Index = 1.
LOOP AT ti_vbak ASSIGNING <fs_vbak>.
LOOP AT ti_vbap ASSIGNING <fs_vbap> FROM INDEX.
IF <fs_vbap>-vbeln NE <fs_vbak>-vbeln.
Index = sy-tabix.
EXIT.
ENDIF.
ENDLOOP.
ENDLOOP.

IV. Analyse des performances

A. Analyse des étapes de transactions

Généralités

Un état, une transaction ou une série d’états ou de transactions formant une partie ou l’intégralité d’un processus de gestion sont des objets pouvant requérir une analyse.
L’analyse des objets individuels peut être effectuée de manière proactive dans le système d’assurance qualité pour les objets non productifs ou de manière réactive dans le système de production pour les objets de production.
Avant d’effectuer une analyse des objets individuels, s’assurer qu’aucun problème fondamental global n’existe dans le système R/3. Pour ce faire, utiliser les services SAP GoingLive et EarlyWatch.

Vue d’ensemble

Au cours du traitement en ligne, une étape de transaction correspond à une modification des écrans. Au cours d’une mise à jour ou d’un spool, chaque requête correspond à une étape de transaction. Le traitement à l’arrière plan peut comporter une ou plusieurs étapes.

Moniteur de charge R/3

Pour afficher les statistiques de chaque étape de transaction (enregistrements individuels de statistiques), utiliser la transaction STAT ou, dans l’écran initial SAP, sélectionner Outils -> administration -> Moniteur -> Performance -> Work load -> Statistics Records.

Vue détaillée Base de données :

L’étude de ces temps détermine l’utilisation :
• soit de la trace des performances SQL
• soit de l’analyse de la durée d’exécution ABAP

afin d’effectuer une analyse supplémentaire.

B. Trace des performances SQL

Vue d’ensemble

Pour obtenir une vue d’ensemble du comportement du système R/3, il est possible d’enregistrer différents processus au cours de l’exécution d’un objet individuel. Pour analyser les problèmes de performances liés aux accès à la base de données, activer la trace SQL et la trace de la mémoire tampon à partir de la transaction ST05.

Ecran initial

Pour accéder à la trace des performances SQL, utiliser la transaction ST05 ou sélectionner Outils -> Administration -> Moniteur -> Traces -> Trace Performances.

Il faut exécuter le programme ABAP au moins une fois avant de lancer la trace des performances, afin d’éviter que les processus de chargement de la mémoire tampon ne soient compris dans la trace.

Liste des traces

Les opérations de base de données requérant plus de 100 millisecondes seraient indiquées en rouge.

Opérations de base de données

Lors du traitement de l’instruction SQL exécutant un accès en lecture, les opérations suivantes sont effectuées :

• PREPARE : cette opération analyse l’instruction SQL puis la convertit en une instruction pouvant être traitée par la base de données.

• OPEN / REOPEN : cette opération remplace les caractères génériques dans l’instruction SQL par des valeurs concrètes puis ouvre le curseur de base de données.

• FETCH : cette opération transmet les enregistrements de base de données du serveur de base de données vers le serveur d’application.


Explain SQL


Explain SQL analyse l’instruction SQL sur laquelle le curseur est placé et est uniquement disponible pour les opérations de base de données PREPARE, OPEN et REOPEN.

Affichage ABAP

Pour accéder au codage ABAP déclenchant l’instruction SQL, utiliser l’icône appropriée. Le codage ABAP de l’instruction SQL sur laquelle le curseur est placé dans la liste des traces apparaît. Il est uniquement disponible pour les opérations de base de données PREPARE, OPEN et REOPEN.

Récapitulatif

Pour obtenir une vue d’ensemble de la fréquence et de la durée des accès aux tables signalées dans la trace des performances SQL, sélectionner Saut -> Summary dans l’écran de la liste des traces. Puis, dans la deuxième fenêtre, sélectionner Traiter -> Comprimer.

cf. page suivante

SELECT Identiques

Sélectionner Saut -> Identical Select permet de savoir s’il y a des instructions SQL identiques et, si c’est le cas, de les lister.

C. Analyse de la durée d’exécution ABAP

Vue d’ensemble

Cette analyse permet d’analyser la durée d’exécution écoulée pour des objets individuels tels que des transactions, des programmes ou des modules de fonction. Elle fonctionne également pour les sous-objets tels que des unités de modularisation ou des instructions.

Ecran initial

Pour accéder à l’écran initial, sélectionner Système -> Utilitaires -> analyse durée d’exécution -> Exécuter ou lancer la transaction SE30.

Analyse d’un programme :

Le résultat de l’analyse est obtenu en cliquant sur le bouton ANALYSER.

D. Débogueur ABAP

Le débogueur ABAP permet d’exécuter un objet étape par étape. Il est généralement utilisé pour contrôler la fonctionnalité. Des fonctions spécifiques du débogueur s’avèrent utiles lors de l’analyse des performances.

E. Mise en mémoire tampon des tables R/3

Le système R/3 est modifiable au niveau du serveur d’application. Ainsi, il est possible d’ajouter des serveurs d’applications supplémentaires à un système R/3 (scalabilité). La base de données, comme le Repository, n’est pas modifiable. Ainsi, une seule base de données existe pour chaque système R/3.
La mise en mémoire tampon des tables R/3 concerne le contenu de table dans le serveur d’application afin de supprimer les besoins d’accès à la base de données et de réduire la charge des ressources de base de données (charge CPU et mémoire centrale).
Il existe deux types de mémoire tampon :
• mémoire tampon par enregistrement (nom technique : TABLP)
• mémoire tampon générique (nom technique : TABL).

V. Analyse du système R/3

A. Analyse du système R/3

Vue d’ensemble

L’analyse du système R/3 est une méthode d’identification des objets individuels critiques pour les performances.
Cette analyse doit uniquement être effectuée dans le système de production.
En terme de pré requis, le système de base R/3, le système de base de données et le matériels doivent être opérationnels, les moniteurs de base de données et R/3 doivent fonctionner et enfin, il faut une activité utilisateur représentative.

Informations requises

Nom de l’objet :
Programme
Transaction
Module fonction

Classification de l’objet :
Nom du développeur ou du responsable, composante applicative ou projet, classe de développement.

Type de problème :
Problème lié à la base
Problème lié à la CPU.

Informations détaillées
Informations spécifiques au problème de la base de données ou de la CPU.

B. Analyse de work load R/3

Vue d’ensemble

Critères :
Nombre d’étapes de dialogue
Temps de réponse total, temps de base de données et temps processeur

Objectif :
Identification des objets critiques pour les performances

Seuil critique :
Supérieur au temps de réponse dialogue acceptable par étape de dialogue.
Durée d’exécution des jobs d’arrière-plan excessivement longue.

Informations :
Nom et classification de l’objet
Caractéristiques du problème.

Ecran initial

Pour accéder au moniteur de charge R/3, sélectionner Outils -> CCMS -> Contrôle/Moniteur -> Menu performances -> Work load -> Analyse ou lancer la transaction ST03.
Dans le premier écran, sélectionner Base de données des performances.

Profil de transaction

Dans l’écran initial du moniteur de charge, sélectionner Total, puis Profil de transactions pour obtenir le temps de réponse total du système R/3 au cours de la période concernée.

Pour analyser une transaction dialogue, trier la liste en fonction du temps de réponse moyen (sous Temps de réponse moyen (ms)), puis commencer par analyser les entrées du haut de la liste.
Le temps de réponse moyen par étape de dialogue correspond au nombre de postes et aux fonctions de la transaction. Plusieurs étapes de transaction sont généralement effectuées lors de l’exécution d’une transaction.

C. Analyse de la mémoire cache SQL BD

Vue d’ensemble

Critères :
Nombre d’accès logiques et physiques en lecture
Accès logiques et physiques en lecture par enregistrement de données

Objectif :
Identification des instructions SQL critiques pour les performances

Seuil critique :
Instruction SQL coûteuse : >= 5 % de tous les accès logiques en lecture, ou >= 3 % de tous les accès physiques en lecture.
Chemin d’accès incorrect : >= 5 lectures logiques par enregistrement de données
Chemin d’accès correct : >= 5 lectures logiques par enregistrement de données

Informations requises :
Nom d’objet, instruction SQL, stratégie d’accès, codage ABAP, noms des tables, des vues et des index
Caractéristiques du problème.

Ecran initial

Un moniteur de base de données existe pour chaque type de système de base de données utilisé dans R/3.
Pour appeler nu moniteur, utiliser la transaction ST04, ou sélectionner Outils -> Administration -> Moniteur -> Performances -> Base de données -> Activité.

Paramètres importants :

Lectures (lecture logique de blocs de données à partir de la mémoire tampon de la base de données)
Lectures physiques (lecture physique des données à partir du disque dur)
Taille du tampon de données (taille et qualité de la mémoire tampon de la base de données)
Appels utilisateurs (nombre d’instructions SQL envoyées à la base de données)
Lectures/appels utilisateur (nombre de lecture pour nombre d’appels utilisateur).
Avatar de l’utilisateur
CAL_DE_TER
Modérateur
Modérateur
 
Messages: 1133
Inscription: 15 Juillet 2009, 13:35
Localisation: Paris, FRANCE

Re: Kit de Developemment SAP 4.6

Messagede kinchung64 » 15 Octobre 2010, 09:10

Bonjour, il existe des outils pour normaliser le code d'un programme.
Tout ce que tu as dit est bel et bien vrai.
Cela dit permettre de le tester c'est encore mieux.
Cet outil s'appelle : Code inspector.

Je l'ai mis en place dans la société pour laquelle je travail.
La transaction est : SCI.

Couplé avec la transaction SLIN, le développeur devrait avoir un code normalisé.
Cela dit la normalisation ne veut pas dire que ceci est bien codé malheureusement.

Cordialement.
Kin-Chung.
kinchung64
Posteur junior
Posteur junior
 
Messages: 18
Inscription: 15 Octobre 2010, 07:10


Retourner vers ABAP

Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 0 invités