Un rapport batch personnalisé traitant plus de 100 000 enregistrements F0911La table principale de JD Edwards qui stocke toutes les écritures comptables du Grand Livre. ne devrait pas s'exécuter pendant quatre à six heures. Lorsque c'est le cas, le coupable est rarement l'indexation de la base de données ou les contraintes matérielles ; il s'agit d'une mauvaise construction des Event Rules (ER)Le langage de programmation interne utilisé par JD Edwards pour définir la logique métier de manière visuelle.. L'exécution d'une optimisation systématique des performances UBEUniversal Batch Engine : le moteur de JD Edwards chargé d'exécuter les rapports et les traitements par lots. JD Edwards pour réduire les lectures de tables nécessite de s'éloigner du traitement ligne par ligne, où les développeurs placent des instructions Fetch SingleUne commande qui demande à la base de données de récupérer un seul enregistrement spécifique. ou Select/Fetch Next à l'intérieur des événements Do Section ou Do Loop d'un UBE, forçant le serveur d'entreprise à exécuter des centaines de milliers de requêtes SQL SELECT redondantes contre la base de données. En analysant les journaux JDEDEBUGUn fichier journal détaillé qui enregistre chaque action technique et requête SQL effectuée par le système., nous pouvons isoler ces boucles, resserrer la sélection de données de la section pilote et refactoriser la logique ER pour utiliser le cache mémoire JDE ou des business functions CProgrammes écrits en langage C pour exécuter des calculs complexes ou des accès aux données très rapides. personnalisées au lieu d'effectuer des allers-retours constants vers la base de données.

Le coût des Table IO ligne par ligne dans les Event Rules

Une seule ligne de code Event Rules peut paralyser silencieusement un processus batch. Chaque instruction standard "Fetch Single" ou "Select/Fetch Next" placée à l'intérieur d'un événement Do Section ne s'exécute pas dans le vide ; elle se traduit directement par une requête SQL indépendante soumise au moteur de base de données. Dans un déploiement typique Oracle ou SQL Server, la surcharge liée à la latence réseau, à l'analyse de l'instruction et à l'évaluation du plan d'exécution s'applique à chaque appel, quelle que soit la taille de la charge utile.

Considérez un rapport d'intégrité financière standard où la section pilote traite 50 000 à 100 000 lignes d'écritures comptables de la table F0911. Si un développeur place un Fetch Single imbriqué sur l'Address Book Master (F0101) à l'intérieur de cette boucle pour récupérer un nom alpha, le moteur batch EnterpriseOneLe nom officiel de la suite logicielle ERP moderne de JD Edwards. initie des dizaines de milliers d'allers-retours réseau individuels vers la base de données. Même si le serveur de base de données résout chaque requête en une ou deux millisecondes apparemment négligeables, le temps cumulé de traitement réseau et de base de données ajoute à lui seul une latence cumulative significative à une seule boucle d'événement.

Les développeurs négligent souvent cette latence cumulative car les instructions Event Rules individuelles semblent inoffensives dans l'Object Management Workbench (OMW)L'interface de développement intégrée utilisée pour créer et modifier des objets dans JD Edwards.. En réalité, ces appels répétitifs à la base de données représentent fréquemment la grande majorité du temps total d'exécution de l'UBE, dépassant souvent 80 %, laissant le CPU du serveur d'entreprise inactif pendant qu'il attend la réponse de la base de données.

Remplacer ces lectures ligne par ligne par des vues de base de données, des jointures de tables ou des mécanismes de mise en cache en mémoire peut instantanément faire passer le temps d'exécution d'un UBE de plusieurs heures à quelques minutes. En déplaçant le gros du travail d'agrégation de données vers la couche base de données ou en utilisant les APIInterface de programmation permettant à différents composants logiciels de communiquer entre eux. de cache interne de JDE, vous éliminez le comportement réseau bavard qui engorge les files d'attente batch lors des clôtures mensuelles.

Unoptimized vs Optimized Table Read Flow

Diagnostiquer les lectures de tables avec les journaux JDEDEBUG et SQL

Pour arrêter de deviner pourquoi un UBE personnalisé traîne, vous devez examiner le SQL brut généré par le middleware de base de données JDBLa couche logicielle de JD Edwards qui traduit les commandes du programme en langage SQL compréhensible par la base de données.. Définissez Output=FILE sous la section [DEBUG] du fichier jde.iniLe fichier de configuration principal contenant les paramètres de fonctionnement de l'environnement JD Edwards. du serveur local ou d'entreprise pour forcer EnterpriseOne à capturer chaque interaction avec la base de données. Cela génère un fichier jdedebug.log qui mappe les Table I/OOpérations d'entrée/sortie consistant à lire ou écrire des données dans les tables de la base de données. des Event Rules directement aux instructions SQL natives telles que SELECT, UPDATE et INSERT.

Charger un fichier journal de plusieurs gigaoctets dans un éditeur de texte standard est une erreur de débutant qui fera planter votre poste de travail. Utilisez plutôt Performance Workbench, un utilitaire fourni par Oracle qui analyse le fichier de trace et agrège les instructions SQL par nombre d'exécutions et par durée. Cette analyse met immédiatement en évidence la fréquence exacte des instructions SELECT frappant des tables à gros volume comme la F0911 ou la F4211, exposant des boucles cachées qui s'exécutent des milliers de fois pour une seule page PDF.

Un UBE hautement efficace maintient un ratio lecture/enregistrement traité proche de 1:1, ce qui signifie que chaque lecture de la section pilote correspond à une recherche unique et ciblée dans la base de données. Dans les rapports mal optimisés, ce ratio grimpe fréquemment à 50:1 ou plus, indiquant que le moteur bombarde la base de données de dizaines de requêtes redondantes pour traiter une seule transaction.

Lorsque le journal révèle des nombres d'exécutions élevés avec des temps de réponse médiocres, vous devez vérifier si la base de données utilise réellement vos index. Exécutez SQL Server Profiler ou interrogez la vue v$sql_planUne vue système Oracle qui montre les étapes précises suivies par la base de données pour exécuter une requête. d'Oracle pour inspecter les plans d'exécution des requêtes identifiées dans votre journal. Cette étape révèle si l'optimiseur de base de données ignore votre index personnalisé sur F41021 ou effectue un scan complet de table coûteux en raison d'une condition de jointure manquante dans votre Table I/O.

Optimisation de la sélection de données de la section pilote

J'ai récemment refactorisé un UBE d'analyse des ventes personnalisé où le développeur laissait la section pilote principale récupérer chaque enregistrement de la table F4211 pour l'exercice fiscal en cours, pour n'en rejeter que la grande majorité, environ 80 % à 90 % selon notre expérience, à l'aide d'une instruction If à l'intérieur de la Do Section. Cette sélection de données large force le moteur UBE à extraire des centaines de milliers de lignes inutiles de la base de données vers la mémoire du serveur d'entreprise. La base de données consomme des cycles pour exécuter les instructions select et transmettre les paquets sur le réseau, pour que le moteur d'exécution rejette immédiatement les données.

Vous devez repousser le travail de filtrage vers le niveau de la base de données, là où il doit être. Manipuler par programmation la clause SQL WHERE à l'aide de la fonction système Set User SelectionUne commande permettant de modifier dynamiquement les filtres de recherche de données au moment de l'exécution. dans l'Initialize SectionL'événement qui s'exécute une seule fois au tout début du traitement d'une section de rapport. est exponentiellement plus rapide que d'évaluer des conditions au sein de la Do Section. Par exemple, si vous devez filtrer les enregistrements F4211 par Next Status (NXTR) et Line Type (LNTY), l'appel explicite de cette fonction système restreint l'ouverture initiale du curseur au seul ensemble de données correspondant, empêchant le middleware de traiter du poids mort.

Pour que cette sélection programmatique soit efficace, les champs cibles doivent s'aligner sur un indexUne structure de données qui permet à la base de données de trouver des lignes très rapidement sans tout lire. de base de données existant. L'exécution d'une requête sur F4211 ou F0911 sur un champ non indexé comme la Transaction Date (TRDJ) déclenche un scan complet de table, détruisant les performances de la base de données. De plus, l'omission du business unit (MCU) ou de la compagnie (CO) dans les critères de sélection sur des bases de données partitionnées est un désastre courant, augmentant souvent les temps de lecture des tables de trois à quatre fois car le moteur de base de données ne peut pas élaguer les partitions et est forcé de scanner chaque partition du schéma.

Refactorisation de la logique de boucle imbriquée et des Table IO

Placer une boucle Select et Fetch Next à l'intérieur de la Do Section d'un UBE est le moyen le plus rapide de dégrader les performances batch de quelques minutes à plusieurs heures. Si la section pilote traite 50 000 à 100 000 enregistrements et que la boucle interne interroge une table secondaire comme la F4211 sans limites strictes, le serveur d'entreprise exécute des centaines de milliers d'allers-retours redondants vers la base de données. Cette croissance géométrique des lectures de tables étouffe le moteur de base de données, surtout lorsque les développeurs négligent de mapper les clés du Select interne pour qu'elles correspondent exactement à un index compositeUn index de base de données qui combine plusieurs colonnes pour accélérer les recherches complexes., forçant des scans complets de table au lieu de recherches d'index rapides.

Ces structures imbriquées laissent fréquemment derrière elles une traînée de curseurs de base de données non fermés. Chaque pointeur de table ouvert qui manque d'une instruction Close explicite correspondante dans les Event Rules fuit de la mémoire et maintient des handles de curseur ouverts sur le serveur d'entreprise. Sur une exécution de dizaines de milliers d'itérations, cette omission consomme les ressources système jusqu'à ce que les limites de la base de données soient atteintes, entraînant un échec soudain et inexpliqué de l'UBE. Fermer explicitement chaque handle de table à la fin du bloc conditionnel est non négociable pour un traitement batch stable.

Les requêtes répétitives pour des données de configuration statiques, telles que la récupération de valeurs UDCUser Defined Codes : des tables de référence contenant des listes de codes et leurs descriptions. de la F0005, ne devraient jamais se produire à l'intérieur de ces boucles. Plutôt que d'émettre des milliers de lectures F0005 distinctes pour les mêmes types de documents, chargez ces données de référence une seule fois dans un cache JDE à l'aide de l'API jdeCache au sein d'une business function C personnalisée pendant l'Initialize Section de l'UBE. La lecture à partir de la mémoire plutôt que de frapper la base de données réduit le temps d'exécution des E/S à presque zéro. Pour des besoins plus simples, le chargement de paires clé-valeur dans un tableau mémoire au démarrage permet d'obtenir la même réduction de surcharge sans la pénalité de la base de données.

Utilisation du cache JDE et des Business Functions

Les Table I/O des Event Rules introduisent un coût de performance car l'interpréteur de l'outil traite chaque instruction séquentiellement avec une surcharge d'exécution importante. Lorsqu'un UBE exécute un simple F0014.FetchSingle à l'intérieur d'une boucle de 100 000 enregistrements ou plus, le moteur ER négocie de manière répétée les connexions à la base de données et analyse les instructions SQL. Déplacer cette logique de recherche dans une business function C compilée contourne entièrement cette surcharge d'interpréteur, s'exécutant à la vitesse du code machine natif.

En développant une business function C personnalisée comme B550001 utilisant les APIs JDECACHEEnsemble de fonctions permettant de stocker et manipuler des données directement dans la mémoire vive (RAM)., vous initialisez un cache nommé en mémoire sur le serveur d'entreprise pendant l'événement Initialize Section de l'UBE. La première lecture de la base de données charge l'enregistrement requis en mémoire ; les requêtes suivantes sont résolues via des pointeurs mémoire au lieu d'allers-retours vers la base de données. Cette approche élimine les lectures SQL pour les données de base statiques, stockant les clés et les valeurs dans un bloc mémoire structuré qui n'existe que pour la durée de l'exécution de l'UBE.

Pour les UBE à gros volume traitant 100 000 enregistrements ou plus, la mise en cache des données de base comme les conditions de paiement (F0014) ou les taux de taxe (F4008) réduit les appels à la base de données de 90 % ou plus. Au lieu de frapper la base de données des dizaines de milliers de fois pour résoudre les dix mêmes conditions de paiement, l'UBE interroge la base de données quelques fois pour alimenter le cache, puis effectue des recherches en mémoire ultra-rapides pour les enregistrements restants.

Une business function C personnalisée gère les structures de mémoire complexes et les recherches binaires bien plus rapidement que les ER ne peuvent boucler à travers les tables de base de données. L'utilisation de l'API jdeCacheFetchPositionUne fonction technique utilisée pour localiser instantanément une donnée précise stockée dans le cache mémoire. permet au système d'effectuer des recherches binaires à haute vitesse sur des clés de cache indexées, renvoyant les données en microsecondes. Cela déplace le goulot d'étranglement du traitement du niveau de la base de données vers la RAM du serveur d'application, où les temps d'accès à la mémoire se mesurent en nanosecondes plutôt qu'en millisecondes requises pour les E/S disque physiques.

Database Lookup Performance Comparison

Mesurer les gains de performance après refactorisation

Vous ne pouvez pas vous fier aux commentaires subjectifs des utilisateurs pour valider un effort de refactorisation ; vous avez besoin de chiffres concrets provenant de la table Job Control Status Master (F986110La table système qui enregistre l'historique, le statut et les temps d'exécution de tous les travaux batch.). Interroger les champs JCSTRTTIME (Heure de début) et JCENDTIME (Heure de fin) où le statut du job (JCST) est 'D' (Done) vous permet de calculer la durée exacte d'exécution en secondes. Comparez cette base de référence post-optimisation à un minimum de trois exécutions historiques de l'UBE non modifié pour tenir compte des variations transitoires de la charge réseau ou de la base de données.

Ensuite, isolez l'impact sur la base de données en comparant le nombre total d'exécutions d'instructions SQL avant et après les modifications du code. La génération d'un jdedebug.log pour un échantillon représentatif de plusieurs milliers d'enregistrements révèle la baisse exacte des lectures physiques de tables. Dans un projet récent impliquant un R42565 (Invoice Print) fortement personnalisé, la refactorisation des Table I/O imbriquées sur la F41021 en une lecture résidente en mémoire a réduit les allers-retours vers la base de données de plus d'un million à moins de 15 000 pour une seule exécution batch.

La vitesse ne doit pas se faire au détriment de la stabilité, en particulier lors du remplacement des E/S disque par le cache JDE ou de grandes structures mémoire. Surveillez l'utilisation du CPU et l'empreinte mémoire du serveur d'entreprise via top sur Linux ou le Gestionnaire des tâches sur Windows pendant l'exécution. Un cache JDE mal géré qui ne parvient pas à appeler deallocateUserCache ou à libérer les pointeurs dans les business functions C personnalisées se manifestera par une fuite de mémoire, finissant par faire planter le processus kernel jdenet_kLe processus moteur principal qui gère les communications et les traitements sur le serveur JD Edwards..

Lorsque ces mesures s'alignent — réduction des instructions de base de données, allocation mémoire stable et exécution propre du code C — un exercice d'optimisation réussi donne généralement une réduction de 70 % à 90 % du temps d'exécution global pour les exécutions batch à gros volume. Crucialement, effectuez une comparaison complète des PDF et des tables à l'aide d'un outil comme PDF Diff pour garantir que la logique optimisée produit des résultats financiers et opérationnels identiques à la version héritée.

Si la réduction des Table IO dans vos UBE à gros volume a mis en évidence des goulots d'étranglement plus larges dans votre parc de code personnalisé, les articles techniques sur la gestion de la mémoire des BSFN C et l'intégration des vues SQL fournissent des conseils architecturaux plus approfondis pour optimiser les performances de l'ERP d'entreprise.