Prenons un ETL, outil chargé d’extraire bêtement des données d’un gros progiciel d’entreprise, SAP pour ne pas le nommer. SAP lui-même s’appuie sur une base de données Oracle. L’ETL pourrait en principe attaquer les données directement au niveau Oracle, mais SAP impose que l’on passe par lui[1].
De ces trois outils, chacun utilise une variante de la lingua franca des bases de données, le SQL : Oracle connaît le PL/SQL (langage efficace et sans chichis que j’ai appris à apprécier), SAP utilise l’ABAP (mélange de Cobol et de SQL limité par sa tendance à vouloir s’appuyer sur plusieurs bases de données différentes sans en exploiter une à fond), et l’ETL définit ses requêtes sous forme graphique avec des morceaux de pseudo-SQL[2].
Besoin
Au départ, le besoin était tout simple : une bête jointure de deux tables sur les « documents article », et récupération des lignes où au moins une de trois dates potentielles était dans une certaine fourchette.
Du côté de l’ETL, le développeur a exprimé cela ainsi :
Joli graphique joignant les tables
MKPF
(en-têtes) etMSEG
(lignes)[3],
et clause de filtrage définie ainsi :
MKPF.MBLNR = MSEG.MBLNR
(jointure)
AND
(
( MKPF.CUPDT >= $PARAM2 AND MKPF.CPUDT <= $PARAM1 )
OR ( MKPF.AEDAT >= $PARAM2 AND MKPF.AEDAT <= $PARAM1 )
OR ( MKPF./BEV2/ED_AEDAT >= $PARAM2 AND MKPF./BEV2/ED_AEDAT <= $PARAM1 )
)
Boum !
L’ETL s’adresse donc à SAP, et génère pour cela à la volée un programme ABAP ; le noyau SAP traduit cette requête dans le SQL d’Oracle, lequel renvoie les données au programme ABAP, dont la sortie est renvoyée à l’ETL.
Après quelques mois en production, ce programme a un soir littéralement explosé (le noyau de SAP refusa de lui allouer plus de mémoire, considérant qu’avec plusieurs gigaoctets il abusait déjà).
En fouillant on découvre déjà que la volumétrie remontant dans SAP se compte en millions de lignes (tables de mouvements de stocks d’une entreprise de belle taille sur plusieurs années), et qu’aucune des colonnes de filtrage n’est indexée dans la base de donnée. Le résultat final que recueille l’ETL ne compte cependant que peu d’enregistrements.
Dans le contexte présent d’un cluster de machines bien burnées, Oracle exécute ce double full scan en peu de temps — pas assez pour qu’on ait besoin de demander à un chef d’imposer à un administrateur système réticent de rajouter des index lourds sur des tables très sollicitées[4]. Ce n’est pas un simple classique problème de performances.
Le programme ABAP généré par l’ETL ressemble à ceci (je simplifie) :
SELECT
MSEG9~MBLNR
(champs)
MSEG9~MJAHR
MSEG9~ZEILE
...
INTO (MSEG9MBLNR,
(stockage de la ligne dans des variables temporaires)
MSEG9MJAHR,
MSEG9ZEILE...)
FROM MSEG AS MSEG9
INNER JOIN MKPF AS MKPF9
(jointure)
ON MKPF9MBLNR
.
...
IF ( ( ( ( MKPF9CPUDT <= $PARAM1 )
(clause de filtrage)
OR ( MKPF9AEDAT <= $PARAM1 ) )
OR ( MSEG9/BEV2/ED_AEDAT <= $PARAM1 ) )
AND ( ( ( ( MKPF9CPUDT >= $PARAM2 )
OR ( MKPF9AEDAT <= $PARAM1 ) )
OR ( MSEG9/BEV2/ED_AEDAT <= $PARAM1 ) )
AND ( ( ( ( MKPF9CPUDT <= $PARAM1 )
OR ( MKPF9AEDAT >= $PARAM2 ) )
OR ( MSEG9/BEV2/ED_AEDAT <= $PARAM1 ) )
AND ( ( ( ( MKPF9CPUDT >= $PARAM2 )
OR ( MKPF9AEDAT >= $PARAM2 ) )
OR ( MSEG9/BEV2/ED_AEDAT <= $PARAM1 ) )
AND ( ( ( ( MKPF9CPUDT <= $PARAM1 )
OR ( MKPF9AEDAT <= $PARAM1 ) )
OR ( MSEG9/BEV2/ED_AEDAT >= $PARAM2 ) )
AND ( ( ( ( MKPF9CPUDT >= $PARAM2 )
OR ( MKPF9AEDAT <= $PARAM1 ) )
OR ( MSEG9/BEV2/ED_AEDAT >= $PARAM2 ) )
AND ( ( ( ( MKPF9CPUDT <= $PARAM1 )
OR ( MKPF9AEDAT >= $PARAM2 ) )
OR ( MSEG9/BEV2/ED_AEDAT >= $PARAM2 ) )
AND ( ( ( MKPF9CPUDT >= $PARAM2 )
OR ( MKPF9AEDAT >= $PARAM2 ) )
OR ( MSEG9/BEV2/ED_AEDAT >= $PARAM2 ) ) ) ) ) ) ) ) ).
... (sauvegarde de la ligne dans une table interne qui sera envoyée à l’ETL)
ENDIF.
ENDSELECT.
(fin du parcours des lignes ramenées)
J’ignore pourquoi la clause IF
est si tourmentée, mais elle est mathématiquement équivalente à celle d’origine (une des trois dates doit être dans la fourchette demandée).
Le point à retenir est que ce IF
est hors de la requête. Chacune des millions de lignes de la table passe dans ce IF
!
On objectera naïvement que de toute manière, faute d’index, il n’y a pas d’autre moyen que ce fastidieux méga-test.
Mais l’important est l’endroit où ce test s’effectue : les millions de lignes sont récupérées par la base Oracle, en sortent, entrent dans le noyau SAP (potentiellement une autre machine), et c’est le processeur ABAP qui se charge des tests sur les dates.
Reformulation
Le changement du programme ABAP est assez basique : j’ai déplacé la clause de filtrage dans la requête ABAP, espérant ainsi que SAP traduira cela à Oracle en une seule requête avec la clause de filtrage. (Et pour être propre on réécrit lisiblement la clause, et on rajoute MJAHR
dans la jointure, qui manquait sans que cela gêne en pratique.)
SELECT...
FROM MSEG AS MSEG9
INNER JOIN MKPF AS MKPF9
ON ( MKPF9MBLNR
AND MKPF9MJAHR )
WHERE ( MKPF9~CPUDT BETWEEN $PARAM2 AND $PARAM1 )
OR ( MKPF9~AEDAT BETWEEN $PARAM2 AND $PARAM1 )
OR ( MSEG9~/BEV2/ED_AEDAT BETWEEN $PARAM2 AND $PARAM1 )
Oracle fait toujours un double full scan, le temps d’exécution est très proche, mais les lignes filtrées ne sortent même pas de la couche SQL, Oracle les jette à peine délivrées par le disque dur. On a évité à des gigaoctets de données de traverser au moins deux couches du mille-feuilles et d’occuper de la précieuse mémoire.
Pour les curieux, le SQL généré par SAP après la modification est basique :
SELECT
T_00 . "MBLNR" , T_00 . "MJAHR" , T_00 . "ZEILE" , ...
FROM
"MSEG" T_00 , "MKPF" T_01
WHERE
(jointure)
( T_01 . "MANDT"[5] = :A0 AND T_01 . "MBLNR" = T_00 . "MBLNR"
AND T_01 . "MJAHR" = T_00 . "MJAHR" ) AND T_00 . "MANDT" = :A1
(filtre sur les dates)
AND ( T_01 . "CPUDT" BETWEEN :A2 AND :A3
OR T_01 . "AEDAT" BETWEEN :A4 AND :A5
OR T_00 . "/BEV2/ED_AEDAT" BETWEEN :A6 AND :A7
)
Moralité
Cet exemple est inhabituel : le développeur comme l’administrateur d’une base cherchent en général à limiter les full scans sur des tables aussi volumineuses, et rajoutent des index (mais il faut contrebalancer avec le coût en disque et en maintenance). On a ici la conjonction de plusieurs problèmes :
- pas d’index sur de grosses tables (quoique, reconnaissons-le, des stats rafraîchies ont mené à un parcours un peu différent en joignant les tables par leur clé commune ; dans le cas d’un parcours complet des tables, cela n’est pas forcément une bonne chose, et on ne change rien au problème de la volumétrie) ;
- un ETL qui n’a pas le droit de s’adresser directement à Oracle, alors qu’il connaît très bien son langage (un bon ETL est polyglotte : Oracle dans toutes ses variantes, Sybase, MS SQL Server, DB2...) ;
- cet ETL (ou plutôt son plug-in pour SAP) commet une erreur stupide en séparant requête et filtrage (bug d’optimisation)
(Ajout de 2014 : Cet ETL, je l’utilise encore des années après, et même dans des incarnations plus modernes il reste le plus stupide et le moins agréable de tous ceux que j’ai pu manipuler — mais il est vendu par SAP) ; - le compilateur ABAP n’est pas assez fûté pour repérer le problème et demande à Oracle le contenu complet de
MSEG
etMKPF
; - le compilateur ABAP semble incapable de gérer efficacement des paquets de plusieurs gigaoctets, il semble tout vouloir traiter d’un bloc, alors qu’Oracle traite ses données par paquets maniables de quelques dizaines de lignes (j’aimerais des détails, cette limite de SAP m’étonne) : le même bug ne serait pas apparu en PL/SQL ;
- ajoutons un effet pervers dû au dimensionnement imposant des machines concernées : le problème n’est apparu ni en développement ni en recette (de plus ces bases sont anciennes, très anciennes, et je le déplore tous les jours), mais en production après un certain temps, quand les tables ont dépassé une certaine taille.
Comme toutes les grandes catastrophes[6], ce problème naît d’une accumulation de plusieurs bugs, et non d’un seul.
Effet mille-feuilles et communication
Les problèmes de communication entre programmes et la génération automatique de code sont courants, mais le « mille-feuilles » est une bonne pratique en programmation : vive la séparation des tâches entre modules spécialisés ! Cf couches OSI, TCP/IP, le protocole X, etc.
Mais ce n’est pas le cas ici : trois éléments ont chacun leur langage pour exprimer ce qui est fondamentalement une requête SQL ; la traduction n’est pas parfaite ou limitée, et n’utilise en tout cas pas toutes les possibilités de l’outil sous-jacent (Oracle).
On n’a pas délégation du travail et encapsulation des détails propres à un niveau qui ne concernent pas les autres (comme entre les différences couches de TCP/IP ou X), mais réécriture de consignes avec réinterprétation au passage à chaque étape : à la syntaxe près, la requête de l’ETL est strictement la même que le SQL d’Oracle, les couches qui font le boulot sont en dessous (dans le noyau Oracle).
Analogie
Cette histoire me rappelle furieusement le fonctionnement d’un service informatique au sens large, où la définition d’un développement à effectuer passe de l’utilisateur au support au fonctionnel interne au fonctionnel externe à l’analyste présent chez le client au chef de projet externe au développeur sur un autre continent, avec spécifications différentes à chaque niveau suivant les consignes/niveau/langue/priorités/besoins/limites/obsessions/normes de chaque strate ; alors que le premier besoin exprimée par l’utilisateur pourrait souvent (pas toujours, loin de là !) suffire au développeur final pour travailler, sans rajouter un effet téléphone arabe et une lourdeur monstrueuse en gestion et « pilotage ».
Notes
[1] Je dis toujours que SAP est totalitaire car il veut tout contrôler.
[2] Ce qui devient vite illisible à mon avis.
[3] Si vous ne comprenez pas immédiatement la fonction des tables et colonnes par leur nom, c’est tout à fait normal habituel sur SAP.
[4] Au passage, je suis surpris du faible nombre d’index présents sur les tables de SAP par rapport à celles du concurrent Oracle Applications.
[5] Le mandant est une clé implicite de chaque table. Il correspond à une « vision du monde » et permet de séparer plusieurs jeux de données (test, paramétrage...) voire certains programmes.
[6] N’exagérons pas, c’est « juste » du décisionnel, ni la production ni la logistique n’ont été affectées.
5 réactions
1 De UKRAINIEN - 12/02/2007, 13:35
Décidément,
vou seriez pour oracle que je ne serai pas surpris. (:)) Mais c'est votre droit.
La notion de mandant va au-délà de ce que vous enoncez. Il est aussi possible de rajouter des index sur les tables, jusqu'à 12, mais comme vous le savez "trop d'index tue l'index". C'est une décision à prendre par les administrateurs SAP.
il y a eu de nombreuses améliorations dans les requêtes ABAP, sans que vous le voyez. Comme c'est un langage interprété compilé, les optimisations peuvent être faite sans pour autant changer la syntaxe.L'ABAP est un langage qui a beaucoup évolué au cours des 5 dernières années.
SAP n'est pas considéré comme une bête de course, je partage votre point de vue. Mais comme il a été choisi par les plus grandes sociétés dans le monde, il a aussi des points positifs.
2 De Le webmestre - 12/02/2007, 21:22
@UKRAINIEN : Oui, j’avoue une préférence pour Oracle (du moins j’aime la base de données, et l’utiliser ; l’administrer est plus chinois ; l’ERP est mieux foutu mais moins puissant que SAP, avec ses propres limites ; les autres outils sont très inégaux ; quant à l'entreprise elle-même, elle est à baffer.
Pour le mandant, je n’ai pas voulu détailler. Ça fait partie des bonnes idées du produit (je passe sur quelques incohérences d’implémentation, du genre des Sapscripts mandants-dépendants quand les programmes sont interdépendants, mais bon...).
L’ABAP a pas mal évolué, oui, mais R/3 ne se programme pas encore en ABAP objet là où je bossais. Le peu que j’ai vu du développement sur le CRM avec sa boulimie de classes m’a effrayé ; j’ai failli pleurer quand je me suis aperçu que l’utilisation en paramètres de fonctions de variables de même type sous-jacent (entiers, chaînes...) mais de domaines différents que celui attendu provoquait des plantages (à l’éxécution !!!), obligeant à une orgie de transtypage. (Mais bon, l’expert qui me pilotait sur ce sujet précis était peut-être une burne qui ne connaissait pas les astuces...).
Les points positifs, il y en a, mais comme dit sur un autre billet, il ne sont pas liés au développement (sinon à la facilité de trouver des gens pour écrire les programmes, en général en Inde). Quant à l’argument d’avoir été choisi par les plus grandes sociétés... je connais assez le milieu et les commerciaux pour savoir que c’est l’antithèse même du critère d’excellence technique :o)
3 De UKRAINIEN - 13/02/2007, 17:37
D'accord pour le côté commercial, j'ai connu 2 projets qui ont planté pour un mauvais choix de l'ERP, à savoir SAP, qui n'était pas le meilleur choix pour le métier du client.
Mais tous les clients ne font pas confiance qu'aux commerciaux dans leur choix. En fait la pertinence du choix repose sur le fait que l'on peut quitter SAP, car en fait cela représente très peu en rapport du C.A. des grandes sociétés, parfois 1 ou 2%. Et ces sociétés ne le font pas.
L'ABAP OBJECT a de bons points, en rapport à JAVA, la gestion des données en permettant de se référer au dictionnaire de données. Le problème de transtypage est commun à tous les langages, l'ABAP n'y échape pas.
Je suis resté sur ORACLE au PL/SQL, je ne peux pas me permettre de comparer au-delà. Cela étant dit, il faut donc voir toutes les facettes du langage.
Pour l'abap :
le SQL (avec ses syntaxes particulières)
la gestion par des tables internes (que je trouve excellente, car figée les données à un instant me semble très important)
la gestion des écrans, simpliste (parfois un peu trop)
La programmation interactive
la programmation object (encore faut-il l'aimer, parfois pas très adaptée au besoin, et complexifie la programmation, quelle que soit le langage. Ce n'est que mon avis).
Oracle fait-il tout cela? Personnellement je ne sais pas. Et je ne connais pas le niveau de complexité pour le faire.
Pour ce qui est de mes stagiaires, tous ne sortent pas d'école, certains avaient plus de 15 ans de programmation derrière eux.
J'ai lu aussi tes réponses sur les autres messages. Pardon, je ne peux y à répondre à toutes, le temps me manque. Je n'ai pas essayé de te convaincre, juste de présenter mon point de vue.
4 De Le webmestre - 13/02/2007, 21:19
@UKRAINIEN :
- Quitter SAP ??? Le choix d’un ERP ne se remet pas en cause à la légère, quel que soit le coût de la licence : le tarif de la migration (que ce soit d’Oracle Applications vers SAP ou l’inverse) est prohibitif, avec tous les spécifiques et interfaces à réécrire, les flux métiers à revoir (et Dieu sait qu’un ERP est structurant de ce point de vue...). Ça n’est envisageable sérieusement qu’en cas de dépérissement de l’éditeur de l’ERP originel ou de consolidation de plusieurs ERP après fusion de deux entreprises...). Le prix des licences est un détail à côté du coût d’implémentation et de maintenance. (Même si ça se rentabilise, mais c’est vrai pour la plupart des ERP).
- Le lien avec le dictionnaire de données a ses côtés pratiques, et n’est pas trop mal implémenté (pour du SAP), mais d’un autre côté mélanger allègrement le technique et le fonctionnel n’est pas non plus une si bonne idée, les contraintes au développement sont parfois assez pénibles. Dans R/3, passe encore, mais en ABAP objet, les problèmes de transtypage que je citais étaient inconnus dans aucun autre langage, forçaient à une orgie de transtypage manuel et surtout n’étaient pas repérés à la compilation mais faisaient dumper à l’exécution !
- Le SQL de SAP n’a pas de syntaxe si particulièrement spéciale (sinon ces pénibles histoires de parenthèses et de virgules, il est SURTOUT très limité par ce qu’on peut faire faire à la base (sauf à faire du SQL natif mais dans ce cas pourquoi acheter SAP ?).
- Les tables internes ne sont pas trop mal gérées mais le problème est leur existence même : sous Oracle, l’utilisation des tables « en direct » (ou par des fonctions d’API) était tout aussi pratique - mais on tirait parti de la gestion des commit, des curseurs, du fait que les SELECT pouvaient être beaucoup plus complexes. Et cela faisait un code nettement moins verbeux (moins de lignes par tâche, quoique cela dépende pas mal du développeur).
Au final, le code était pondu beaucoup plus vite pour des programmes un peu importants.
- La gestion des écrans n’est pas simpliste, elle est bizarre : jamais vu ailleurs, jamais compris la cohérence. Pour des écrans texte 80 colonnes ça devait aller mais nous sommes au XXIè siècle. Oracle utilise un outil du genre de ce qu'on trouvait en RAD dans les années 90, Forms (moche et assez limité mais à peu près utilisable, créant de vrais fenêtres avec ascenseurs, boutons...), en attendant le full web.
Par contre, pour les sorties papier, Smartforms (un cauchemar d’ergonomie) n’arrive pas à la cheville de Oracle Reports, un outil de dix ans plus ancien.
Un bémol, la gestion des matchcodes, SELECT-OPTIONS, PARAMETER, l’intégration avec les filtres... est un point fort de SAP/ABAP que je regretterais si je retournais sous Oracle Applications.
- La programmation objet, je suis d’accord, n’est pas vraiment adaptée au fonctionnement des ERP, mais c’est une question de style ; le point fort est plutôt dans la gestion des interfaces graphiques, encore faut-il que cela soit fait correctement, l’adaptation au CRM m’a semble inutilement complexe (un défaut très SAP, je dirais même très allemand, la lourdeur façon ''Panzer'').
- Oracle fait ça tout aussi bien, de manière plus agréable à mon goût car il se base sur une collection d’outils plus ou moins « standards » et non liés forcément à l’ERP, et le langage de développement est plus moderne et plus agréable (PL/SQL, proche du Pascal et du SQL). On pourrait rêver d’un mix des deux, du PL/SQL intégrant les matchcodes et éventuellement le typage « fonctionnel » des données.
- Ouais, à moi aussi le temps manque... Merci des critiques constructives, en tout cas.
5 De UKRAINIEN - 14/02/2007, 11:07
Remerciement partagé. J'aurai aussi appris.