Eine benutzerdefinierte BSFNBusiness Functions sind wiederverwendbare Programmeinheiten in JD Edwards, die spezifische Geschäftsregeln oder Datenbankoperationen ausführen. zur Bestandsallokation, die 10.000 bis 15.000 Verkaufsauftragszeilen verarbeitet, sollte in weniger als einer Minute ausgeführt werden. Dennoch dauert dieser Vorgang in vielen JDE 9.2-Umgebungen über eine halbe Stunde aufgrund eines klassischen Anti-Patterns: die Ausführung repetitiver Select- und Fetch Next-Anweisungen auf F4101 oder F4102 innerhalb einer Schleife. Wenn eine Named Event Rule (NER)Eine JDE-spezifische Programmiersprache, die es ermöglicht, Logik grafisch zu erstellen, bevor sie automatisch in C-Code generiert wird. oder eine C-Business-Function bei jeder einzelnen Iteration einen Datenbank-RoundtripDer vollständige Zyklus einer Anfrage vom Anwendungsserver zur Datenbank und die Rücksendung des Ergebnisses. auslöst, beeinträchtigt die Netzwerklatenz zwischen dem Enterprise Server und der Datenbankebene die Performance erheblich.

Die Behebung dieses Engpasses erfordert mehr als nur das Hinzufügen von SQL Server- oder Oracle DB-Indizes. Echtes JDE BSFN Performance-Tuning zur Reduzierung von Tabellen-I/O in Schleifen erfordert architektonische Anpassungen, insbesondere den Ersatz von zeilenweisem Datenbank-I/O durch JDE User Cache APIsProgrammierschnittstellen, die es ermöglichen, Daten temporär im schnellen Arbeitsspeicher statt auf der langsamen Festplatte zu speichern. (wie jdeCacheInit) oder das Vorabladen von Daten in den Speicher (Prefetching). Indem Stammdaten einmalig im Speicher bereitgestellt werden, eliminieren Sie Tausende redundanter SQL-Ausführungen und senken die Ausführungszeiten um 90 % bis 95 %.

Die versteckten Kosten von verschachteltem Tabellen-I/O in Schleifen

In einer Standard-Verkaufsauftragserfassung (P42101) oder einem angepassten Batch-Post-Processing-UBEUniversal Batch Engine; ein JDE-Werkzeug zur Erstellung von Berichten und zur Durchführung von Massendatenverarbeitungen im Hintergrund. verschachteln Entwickler häufig Datenbankabfragen innerhalb einer Hauptschleife. Jedes einzelne JDB_FetchKeyed oder Select-Statement, das innerhalb dieser Schleife ausgeführt wird, löst einen individuellen Netzwerk-Roundtrip und eine Datenbank-Parse-Phase aus. Diese Architektur potenziert die Latenz exponentiell, da die MiddlewareSoftwarekomponenten, die den Datenaustausch und die Kommunikation zwischen verschiedenen Anwendungen oder Systemen vermitteln. für jede Zeile einen vollständigen Request-Response-Zyklus aushandeln muss, selbst wenn der Datenbankserver den Ausführungsplan zwischengespeichert hat.

Betrachten Sie ein Szenario, in dem ein Batch von 5.000 bis 10.000 Datensätzen verarbeitet wird, wie z. B. tägliche Bestandsanpassungen in der F4111. Wenn die Business-Function mehrere Einzelzeilen-Abfragen durchführt – zum Beispiel die Prüfung von Artikel-Filial-Parametern in der F4102, Maßeinheiten-Umrechnungen in der F41002 und Standortdetails in der F41021 – führt die Schleife Zehntausende einzelner Datenbankoperationen aus. Dieses Volumen an „geschwätzigem“ Datenverkehr sättigt schnell die Netzwerkkarte und kann den JDE CallObject-KernelEin spezialisierter Serverprozess in JD Edwards, der für die Ausführung von Business Functions (BSFNs) zuständig ist. lähmen, der in einem dauerhaften Wartezustand verbleibt, während Benutzer Hänger in der interaktiven Anwendung erleben.

Infrastrukturteams versuchen oft, diese Performance-Einbußen durch das Neuerstellen von SQL-Indizes oder das Anpassen von Datenbank-Memory-Pools zu beheben. Während eine korrekte Indizierung die rohen Festplatten-Lesegeschwindigkeiten optimiert, trägt sie nichts dazu bei, die physische Netzwerklatenz oder die CPU-Kontextwechsel zu mildern, die zwischen dem Enterprise Server und dem Datenbankserver auftreten. Der Engpass ist nicht die Fähigkeit der Datenbank, die Zeile zu finden; es ist die schiere Menge an Kontextwechseln, die der CallObject-Kernel durchführen muss, um Tausende diskreter JDB-APIDie interne Programmierschnittstelle von JD Edwards für die Kommunikation mit der Datenbank.-Aufrufe zu initiieren, auszuführen und zu schließen.

Bevor Sie eine weitere Zeile C-Code oder NER schreiben, profilieren Sie die Transaktionsdichte. Wenn Ihr Ausführungsprotokoll Tausende sequenzieller SQL-Abfragen für eine einzige interaktive Transaktion zeigt, müssen Sie die Logik refaktorieren, um statische Tabellen einmalig in den Speicher zu laden.

Messung des Overheads mit der Performance Workbench

Refaktorieren Sie niemals eine Zeile C-Code oder eine Named Event Rule (NER) basierend auf einer Vermutung darüber, welche Tabelle die Systemleistung beeinträchtigt. Um die tatsächliche Ursache zu isolieren, passen Sie Ihre lokale jde.ini-Datei an, navigieren Sie zum Abschnitt [DEBUG] und setzen Sie Output=FILE zusammen mit Keep logs=0, um einen sauberen Ausführungspfad zu erfassen. Das Ausführen des Ziel-UBEs oder der interaktiven Anwendung in diesem Zustand erzeugt eine detaillierte jdedebug.log-Datei, die leicht mehrere Gigabyte überschreiten kann und jeden einzelnen Datenbank-API-Aufruf, jede Business-Function-Grenze und jedes vom CallObject-Kernel ausgeführte SQL-Statement abbildet.

Das Einlesen dieser großen Protokolldatei in das Tool Oracle Performance WorkbenchEin Analyse-Werkzeug von Oracle, um die Laufzeit und Effizienz von JDE-Programmen detailliert zu untersuchen. ermöglicht es Ihnen, Millionen von Zeilen roher Trace-Daten in Minuten zu analysieren. Das Tool aggregiert die Performance-Metriken und isoliert spezifisch die exakte Dauer von JDB_SelectKeyed-, JDB_Fetch- und JDB_OpenTable-API-Aufrufen. Es ordnet diese Datenbankoperationen nach kumulativer Ausführungszeit und legt sofort offen, welche Tabellen, wie z. B. eine benutzerdefinierte F551101-Tag-Tabelle, während der Verarbeitung unverhältnismäßig viele Datenbank-Roundtrips erzeugen.

Ein häufiger Diagnosefehler besteht darin, nur nach schweren, lang laufenden SQL-Anweisungen zu suchen, die mehrere Sekunden für die Ausführung benötigen. Bei schleifenbasierten Engpässen werden Sie genau das Gegenteil sehen: ein einzelnes SELECT-Statement auf der F4101, das in weniger als einer Millisekunde läuft, aber eine Ausführungsanzahl im Zehntausenderbereich aufweist. Diese hohe Ausführungsanzahl bei geringer individueller Dauer ist die definitive Signatur eines schleifenbasierten I/O-Engpasses. Die Identifizierung dieses Musters sagt Ihnen präzise, wo Sie repetitive Datenbankabfragen durch eine speicherbasierte Caching-Strategie ersetzen müssen, bevor Sie den Code in die PY-Umgebung befördern.

Implementierung von JDE Cache für statische Stammdaten

Ein benutzerdefiniertes Verkaufsverarbeitungs-UBE, das Zehntausende von Auftragszeilen verarbeitet, sollte nicht Zehntausende separate SQL-SELECT-Anweisungen gegen die F4101 für dieselben paar hundert schnelldrehenden Artikel ausführen. Für statische oder semi-statische Tabellen wie den F4101 Item Master oder die F0010 Company Constants eliminiert das einmalige Laden der Daten in einen JDE User Cache pro Transaktion die Datenbank-Roundtrips vollständig. Dies verlagert den Performance-Engpass von der Datenbank-I/O-Latenz – die typischerweise 2 bis 5 Millisekunden pro Abfrage über das Netzwerk verbraucht – hin zu Lookups in Speichergeschwindigkeit, die in Mikrosekunden gemessen werden. In einer standardmäßigen 3-Tier-Architektur verhindert dieses lokale Caching Netzwerk-Serialisierungsverzögerungen zwischen dem Enterprise Server und der Datenbank-Engine.

Die JDE Cache API-Funktionen wie jdeCacheInit, jdeCacheAdd und jdeCacheFetchPosition speichern strukturierte Datensätze direkt im Speicherbereich des CallObject-Kernels. Wenn eine C-Business-Function einen Cache initialisiert, definiert sie eine eindeutige Schlüsselstruktur, die den Indizes der Ziel-Tabelle entspricht, wie z. B. die Kurzartikelnummer (ITM) und Filiale/Werk (MCU). Nachfolgende Lookups umgehen die Datenbank-Middleware vollständig und rufen die vorab geladene F4101-Datenstruktur direkt aus dem lokalen RAM ab. Diese Architektur skaliert linear und behält Antwortzeiten im Sub-Millisekundenbereich bei, selbst unter einer Last von mehreren hundert gleichzeitigen HTML-Sitzungen.

Geschwindigkeitsgewinne sind wertlos, wenn Ihre Enterprise Server aufgrund von Speichererschöpfung abstürzen. Entwickler müssen ein striktes Bereinigungsmuster mit jdeCacheTerminate im Destruktionsblock der BSFN implementieren, um Speicherlecks in der JDE-Middleware zu verhindern. Wenn ein CallObject-Kernel Tausende von Transaktionen verarbeitet, ohne seine Cache-Instanzen zu beenden, sammeln sich diese verwaisten Speichersegmente an. Dies erzwingt schließlich ein administratives Recycling des Kernels, wodurch aktive Benutzersitzungen während der Hauptbetriebszeiten unterbrochen werden. Kombinieren Sie jedes jdeCacheInit immer mit einem entsprechenden Terminierungsaufruf im selben Ausführungsthread.

Database IO vs Memory Cache Pattern

Das Prefetch-Muster für Eins-zu-viele-Beziehungen

Die Verarbeitung von Tausenden von F4211-Detailzeilen durch Abfrage der F4201-Header-Tabelle innerhalb der Schleife ist ein klassischer Performance-Killer, der in einer signifikanten Mehrheit der benutzerdefinierten Versandbestätigungs- oder Fakturierungs-UBEs auftritt – unserer Erfahrung nach in etwa drei Vierteln der Fälle. Dieses N+1-Abfragemuster erzeugt Tausende von einzelnen Roundtrips zur Datenbank und bläht die Ausführungszeiten von Sekunden auf Minuten auf. Das Vorabladen (Prefetching) von übergeordneten F4201-Datensätzen in großen Mengen vor dem Eintritt in die Detailschleife eliminiert diesen geschwätzigen Datenbankverkehr vollständig.

Anstatt JDB_FetchKeyed innerhalb der F4211-Schleife auszuführen, extrahieren Sie zuerst die eindeutige Liste der Belegnummern (DOCO), Typen (DCTO) und Firmen (KCOO). Sie führen dann ein einzelnes SELECT-Statement mit einer IN-Klausel aus – oder nutzen einen Teil-Schlüssel-Join –, um diese F4201-Header-Datensätze in ein sortiertes Speicher-Array oder einen leichtgewichtigen JDE User Cache zu laden. Für einen typischen Batch von 200 bis 500 Verkaufsaufträgen ersetzt dies Tausende einzelner Datenbank-Select-Anweisungen durch einen einzigen, hochoptimierten Index-Scan auf dem Primärschlüssel der F4201.

Sobald sich die Header-Daten im lokalen Speicher befinden, skaliert die Suchleistung logarithmisch statt linear. Das Iterieren durch das sortierte Speicher-Array unter Verwendung eines binären Suchalgorithmus, wie der Standard-C-Bibliotheksfunktion bsearch, reduziert die Lookup-Latenz von 2 bis 5 Millisekunden pro Datenbankabruf auf weniger als eine Mikrosekunde. Wenn Sie eine EDI-Schnittstelle mit hohem Volumen und Zehntausenden von Zeilen verarbeiten, reduziert diese Prefetch-Optimierung die UBE-Laufzeiten um 80 % bis 90 % und senkt die Ausführungszeiten von mehreren Minuten auf unter zwei Minuten, ohne einen einzigen Index in der Datenbank zu ändern.

Comparison of JDE BSFN Data Access Strategies

Refactoring von NER zu C BSFN für Speicherkontrolle

Named Event Rules (NER) sind ein großer Engpass bei der Verarbeitung hoher Volumina, da ihnen der direkte Zugriff auf JDE Cache APIs fehlt. Wenn Entwickler temporäre Transaktionszustände über Iterationen hinweg in einer NER speichern müssen, sind sie gezwungen, ineffiziente Workarounds wie benutzerdefinierte Arbeitstabellen (z. B. eine benutzerdefinierte F5501UI-Tabelle) oder wiederholte Datenbank-Views zu verwenden. Dieses Designmuster führt zu schwerem Festplatten-I/O und Datenbank-Sperren, wodurch ein Speicher-Lookup, der im Sub-Millisekundenbereich liegen sollte, bei jeder einzelnen Schleifeniteration zu einem physischen Datenbankzugriff von mehreren Millisekunden wird.

Die Konvertierung dieser hochfrequenten NERs in C-Business-Functions löst diese Einschränkung, indem sie native Pointer-Manipulation, benutzerdefinierte Strukturdefinitionen und direktes Speichermanagement ermöglicht. Anstatt das Toolset im Hintergrund aufgeblähten, unoptimierten C-Code generieren zu lassen, ermöglicht das Schreiben von nativem C die dynamische Speicherallokation mit jdeAlloc und die Definition präziser Strukturen, die Ihre Geschäftslogik widerspiegeln. Dieser Übergang reduziert die CPU-Auslastung auf dem Enterprise Server für Batch-Jobs, die große Datensätze wie die F4211 oder F4111 verarbeiten, typischerweise um 40 % bis 60 %.

Der eigentliche architektonische Vorteil einer C-BSFN ist ihre Fähigkeit, Zustände über mehrere Aufrufe hinweg unter Verwendung der PointerIn der Programmierung ein Verweis auf eine bestimmte Stelle im Arbeitsspeicher, an der Daten abgelegt sind. lpDs->hUser oder lpVoid beizubehalten. In einer typischen mehrstufigen UBE-Ausführung können Sie einen JDE Cache im ersten Aufruf initialisieren, die Speicheradresse dieses Cache-Buckets im benutzerreservierten Pointer speichern und sie in nachfolgenden Detailverarbeitungsaufrufen sofort wieder abrufen. Dies eliminiert den Overhead für das Durchsuchen der globalen Cache-Liste nach Namen bei jedem Aufruf und ermöglicht einen persistenten Cache-Zugriff über verschiedene Ausführungsschritte hinweg ohne einen einzigen Datenbank-Roundtrip.

Validierung der Performance-Gewinne in PY-Umgebungen

Die Durchführung von Performance-Validierungen in einer lokalen Entwicklungsumgebung (DV) mit einer gekürzten Datenbank ist Zeitverschwendung. Um realistische Netzwerk- und Datenbanklatenzen zu erfassen, müssen Sie diese Validierungstests in einer Prototyp-Umgebung (PY) durchführen, die eine wiederhergestellte Datenbank in Produktionsgröße enthält. Ohne die physische Distanz zwischen dem Enterprise Server und dem Datenbankserver und ohne Tabellen in Produktionsgröße wie die F0911 oder F4211 werden Ihre lokalen Cache-Treffer die realen Latenzen verschleiern, die auftreten, wenn Tausende von gleichzeitigen Benutzern auf das System zugreifen.

Um eine saubere Baseline zu erstellen, konstruieren Sie einen einfachen, standardisierten UBE-Treiber – wie einen benutzerdefinierten R5501I6-Bericht –, der darauf ausgelegt ist, die Ziel-Business-Function sequenziell über einen Batch von 5.000 bis 10.000 Datensätzen auszuführen. Führen Sie diesen Treiber einmal mit der alten BSFN-Konfiguration aus, leeren Sie den JDE-Datenbank-Cache über den Server Manager, um zu verhindern, dass zwischengespeicherte Ergebnisse den nächsten Lauf verfälschen, und führen Sie dann denselben Treiber mit Ihrem refaktorierten Code aus. Dieser direkte Vergleich isoliert die Ausführung der Geschäftslogik von den Rendering-Zeiten interaktiver APPL-Masken und liefert Ihnen saubere, unverfälschte Protokolldateien in der Druckwarteschlange.

Ein erfolgreiches cache-basiertes oder Prefetch-Refactoring muss eine Reduzierung der Datenbank-Ausführungszeit um 90 % bis 95 % ergeben, um als abgeschlossen zu gelten. In einer kürzlich durchgeführten Optimierung einer F41021-Artikelverfügbarkeitsschleife während eines 9.2-Upgrades senkte dieser spezifische Ansatz die gesamte BSFN-Ausführungszeit für einen block von 10.000 Zeilen von über zehn Minuten auf unter eine halbe Minute. Wenn Sie Tausende einzelner SQL-SELECT-Anweisungen eliminieren und durch Speicher-Pointer-Lookups ersetzen, flacht die CPU-Auslastung der Datenbank ab und der Netzwerk-Transport-Overhead sinkt auf nahezu Null.

Wenn Ihr Bestand an benutzerdefiniertem Code mehrere tausend Objekte überschreitet, kann die kumulative Belastung durch ineffizienten Tabellen-I/O innerhalb von BSFN-Schleifen leicht einen erheblichen Teil der UBE-Ausführungszeit ausmachen – unserer Erfahrung nach etwa ein Drittel bis zur Hälfte.