Un report batch personalizzato che elabora oltre 100.000 record F0911La tabella principale del Libro Giornale (General Ledger) in JD Edwards, che contiene tutte le transazioni contabili. non dovrebbe impiegare dalle quattro alle sei ore. Quando accade, il colpevole raramente è l'indicizzazione del database o i limiti hardware; si tratta di una cattiva costruzione delle Event Rules (ER)Il linguaggio di programmazione visuale proprietario di JD Edwards utilizzato per definire la logica di business.. Eseguire un'ottimizzazione sistematica delle performance UBEUniversal Batch Engine: il componente di JD Edwards responsabile dell'esecuzione di report e processi di elaborazione massiva dei dati. di JD Edwards per ridurre le letture di tabella richiede di abbandonare l'elaborazione riga per riga, dove gli sviluppatori inseriscono istruzioni Fetch SingleUn'operazione che recupera un unico record specifico da una tabella del database basandosi su una chiave definita. o Select/Fetch Next all'interno degli eventi Do Section o Do Loop di un UBE, costringendo l'enterprise serverIl server centrale che esegue la logica di business e i processi batch dell'ERP. a eseguire centinaia di migliaia di istruzioni SQL SELECT ridondanti verso il database. Analizzando i log JDEDEBUGUn file di log dettagliato che registra ogni operazione eseguita dal sistema, incluse le chiamate al database e le funzioni di business., possiamo isolare questi loop, restringere la data selection della sezione driver e rifattorizzare la logica ER per utilizzare la cache di memoria JDE o business function CModuli di codice scritti in linguaggio C per eseguire operazioni complesse con prestazioni superiori rispetto alle normali Event Rules. personalizzate invece di effettuare continui roundtrip verso il database.
Il costo dell'IO di tabella riga per riga nelle Event Rules
Una singola riga di codice Event Rules può paralizzare silenziosamente un processo batch. Ogni istruzione standard "Fetch Single" o "Select/Fetch Next" inserita in un evento Do Section non viene eseguita nel vuoto; si traduce direttamente in un'istruzione SQL indipendente inviata al motore del database. In una tipica installazione Oracle o SQL Server, l'overhead della latenza di rete, del parsing dell'istruzione e della valutazione del piano di esecuzione si applica a ogni singola chiamata, indipendentemente dalla dimensione del payload.
Consideriamo un report di integrità finanziaria standard in cui la sezione driver elabora da 50.000 a 100.000 righe di primanota dalla tabella F0911. Se uno sviluppatore inserisce una Fetch Single annidata sulla Address Book Master (F0101) all'interno di quel loop per recuperare un nome alfa, il motore batch di EnterpriseOneLa versione moderna della suite ERP JD Edwards basata su architettura web e database relazionali. avvia decine di migliaia di singoli round-trip di rete verso il database. Anche se il server del database risolve ogni query in uno o due millisecondi apparentemente trascurabili, il tempo cumulativo di elaborazione di rete e database aggiunge una latenza significativa a un singolo loop di eventi.
Gli sviluppatori spesso trascurano questa latenza cumulativa perché le singole istruzioni Event Rules sembrano innocue nell'Object Management Workbench (OMW)L'ambiente di sviluppo integrato di JD Edwards utilizzato per gestire e modificare tutti gli oggetti del sistema.. In realtà, queste chiamate ripetitive al database rappresentano spesso la stragrande maggioranza del tempo totale di esecuzione dell'UBE, superando frequentemente l'80%, lasciando la CPU dell'enterprise server inattiva in attesa della risposta del database.
Sostituire queste letture riga per riga con viste database, join di tabelle o meccanismi di caching basati sulla memoria può ridurre istantaneamente il tempo di esecuzione di un UBE da diverse ore a pochi minuti. Spostando il carico pesante dell'aggregazione dei dati sul livello database o utilizzando le API di cache interna di JDE, si elimina il comportamento di rete "chiacchierone" che intasa le code batch durante le elaborazioni di fine mese.

Diagnosticare le letture di tabella con i log JDEDEBUG e SQL
Per smettere di tirare a indovinare il motivo per cui un UBE personalizzato è lento, è necessario esaminare l'SQL grezzo generato dal middleware del database JDB. Impostate Output=FILE nella sezione [DEBUG] del file jde.iniIl file di configurazione principale che definisce le impostazioni di runtime per i client e i server JD Edwards. locale o dell'enterprise server per forzare EnterpriseOne a catturare ogni singola interazione con il database. Questo genera un file jdedebug.log che mappa l'I/O di tabella delle Event Rules direttamente alle istruzioni SQL native come SELECT, UPDATE e INSERT.
Caricare un file di log di diversi gigabyte in un editor di testo standard è un errore da principianti che blocca la workstation. Invece, passate il log attraverso Performance Workbench, un'utility fornita da Oracle che analizza il file di traccia e aggrega le istruzioni SQL per numero di esecuzioni e durata. Questa analisi evidenzia immediatamente l'esatta frequenza delle istruzioni SELECT che colpiscono tabelle ad alto volume come la F0911 o la F4211, esponendo loop nascosti che vengono eseguiti migliaia di volte per una singola pagina PDF.
Un UBE altamente efficiente mantiene un rapporto tra letture del database e record elaborati vicino a 1:1, il che significa che ogni fetch dalla sezione driver corrisponde a una singola ricerca mirata nel database. Nei report mal ottimizzati, questo rapporto sale spesso a 50:1 o superiore, indicando che il motore sta martellando il database con decine di query ridondanti per elaborare una singola transazione.
Quando il log rivela conteggi di esecuzione elevati con tempi di risposta scarsi, è necessario verificare se il database sta effettivamente utilizzando gli indici. Eseguite SQL Server Profiler o interrogate la vista v$sql_plan di Oracle per ispezionare i piani di esecuzione delle query identificate nel log. Questo passaggio rivela se l'ottimizzatore del database sta ignorando il vostro indice personalizzato sulla F41021 o se sta eseguendo un costoso full table scanUn'operazione inefficiente in cui il database deve leggere ogni singola riga di una tabella per trovare i dati richiesti. a causa di una condizione di join mancante nel vostro I/O di tabella.
Ottimizzazione della Data Selection della sezione driver
Recentemente ho rifattorizzato un UBE personalizzato di analisi delle vendite in cui lo sviluppatore permetteva alla sezione driver primaria di recuperare ogni record dalla tabella F4211 per l'anno fiscale corrente, solo per scartarne la stragrande maggioranza, nella nostra esperienza circa l'80%-90%, utilizzando un'istruzione If all'interno della Do Section. Questa ampia selezione di dati costringe il motore UBE a recuperare centinaia di migliaia di righe non necessarie dal database nella memoria dell'enterprise server. Il database spende cicli per eseguire istruzioni select e trasmettere pacchetti sulla rete, solo perché il motore di runtime scarti immediatamente i dati.
È necessario riportare il lavoro di filtraggio al livello del database, dove appartiene. Manipolare programmaticamente la clausola SQL WHERE utilizzando la system function Set User SelectionUna funzione di sistema utilizzata per modificare dinamicamente i criteri di filtraggio dei dati (clausola WHERE) via codice. nella Initialize Section è esponenzialmente più veloce rispetto alla valutazione delle condizioni all'interno della Do Section. Ad esempio, se è necessario filtrare i record F4211 per Next Status (NXTR) e Line Type (LNTY), chiamare esplicitamente questa system function limita l'apertura iniziale del cursore al solo set di dati corrispondente, impedendo al middleware di elaborare pesi morti.
Affinché questa selezione programmatica sia efficace, i campi target devono essere allineati con un indice del database esistente. Eseguire una query su F4211 o F0911 su un campo non indicizzato come la Transaction Date (TRDJ) innesca un full table scan, distruggendo le performance del database. Inoltre, omettere la business unit (MCU) o la company (CO) dai criteri di selezione su database partizionati è un disastro comune, che spesso aumenta i tempi di lettura della tabella di tre o quattro volte perché il motore del database non può potare le partizioni ed è costretto a scansionare ogni partizione nello schema.
Rifattorizzazione della logica dei loop annidati e dell'IO di tabella
Inserire un loop Select e Fetch Next all'interno della Do Section di un UBE è il modo più rapido per degradare le performance batch da minuti a ore. Se la sezione driver elabora da 50.000 a 100.000 record e il loop interno interroga una tabella secondaria come la F4211 senza vincoli stretti, l'enterprise server esegue centinaia di migliaia di roundtrip ridondanti verso il database. Questa crescita geometrica delle letture di tabella soffoca il motore del database, specialmente quando gli sviluppatori trascurano di mappare le chiavi della Select interna per farle corrispondere esattamente a un indice composto, forzando scansioni complete della tabella invece di rapide ricerche per indice.
Queste strutture annidate lasciano spesso dietro di sé una scia di cursori database non chiusi. Ogni puntatore di tabella aperto che manca di una corrispondente istruzione Close esplicita nelle Event Rules causa perdite di memoria e mantiene aperti gli handle dei cursori sull'enterprise server. Nel corso di decine di migliaia di iterazioni, questa omissione consuma risorse di sistema fino a superare i limiti del database, provocando un improvviso e inspiegabile fallimento dell'UBE. Chiudere esplicitamente ogni handle di tabella alla fine del blocco condizionale non è negoziabile per un'elaborazione batch stabile.
Le query ripetitive per dati di configurazione statici, come il recupero dei valori UDC dalla F0005, non dovrebbero mai avvenire all'interno di questi loop. Invece di emettere migliaia di letture distinte della F0005 per gli stessi tipi di documento, caricate questi dati di riferimento una sola volta in una cache JDE utilizzando le API jdeCacheUn set di funzioni che permette di memorizzare e recuperare dati direttamente nella memoria RAM del server per massimizzare la velocità. all'interno di una business function C personalizzata durante la Initialize Section dell'UBE. Il recupero dalla memoria invece che dal database riduce il tempo di esecuzione dell'I/O quasi a zero. Per requisiti più semplici, caricare coppie chiave-valore in un array di memoria all'avvio ottiene la stessa riduzione dell'overhead senza la penalità del database.
Utilizzo della cache JDE e delle Business Function
L'I/O di tabella delle Event Rules introduce una tassa sulle performance perché l'interprete del set di strumenti elabora ogni istruzione sequenzialmente con un significativo overhead di runtime. Quando un UBE esegue una semplice F0014.FetchSingle all'interno di un loop di 100.000 o più record, il motore ER negozia ripetutamente le connessioni al database e analizza le istruzioni SQL. Spostare questa logica di ricerca in una business function C compilata bypassa completamente questo overhead dell'interprete, eseguendo a velocità di codice macchina nativo.
Sviluppando una business function C personalizzata come B550001 utilizzando le API JDECACHE, si inizializza una cache denominata in memoria sull'enterprise server durante l'evento Initialize Section dell'UBE. La prima lettura del database carica il record richiesto in memoria; le richieste successive vengono risolte tramite puntatori di memoria invece di roundtrip verso il database. Questo approccio elimina le letture SQL per i dati anagrafici statici, memorizzando chiavi e valori in un blocco di memoria strutturato che esiste solo per la durata dell'esecuzione dell'UBE.
Per gli UBE ad alto volume che elaborano 100.000 o più record, il caching dei dati anagrafici come i termini di pagamento (F0014) o le aliquote fiscali (F4008) riduce le chiamate al database del 90% o più. Invece di colpire il database decine di migliaia di volte per risolvere gli stessi dieci termini di pagamento, l'UBE interroga il database poche volte per popolare la cache, quindi esegue ricerche in memoria fulminee per i record rimanenti.
Una business function C personalizzata gestisce strutture di memoria complesse e ricerche binarie molto più velocemente di quanto le ER possano scorrere le tabelle del database. L'utilizzo dell'API jdeCacheFetchPosition consente al sistema di eseguire ricerche binarie ad alta velocità sulle chiavi della cache indicizzate, restituendo i dati in microsecondi. Ciò sposta il collo di bottiglia dell'elaborazione dal livello database alla RAM dell'application server, dove i tempi di accesso alla memoria si misurano in nanosecondi anziché nei millisecondi richiesti per l'I/O fisico su disco.

Misurare i guadagni di performance dopo la rifattorizzazione
Non si può fare affidamento sul feedback soggettivo degli utenti per convalidare uno sforzo di rifattorizzazione; servono numeri concreti dalla tabella Job Control Status Master (F986110La tabella di sistema che monitora lo stato, i tempi di esecuzione e i parametri di tutti i job batch inviati al server.). Interrogando i campi JCSTRTTIME (Ora di inizio) e JCENDTIME (Ora di fine) dove lo stato del job (JCST) è 'D' (Done), è possibile calcolare l'esatta durata dell'esecuzione in secondi. Confrontate questa baseline post-ottimizzazione con un minimo di tre esecuzioni storiche dell'UBE non modificato per tenere conto della varianza transitoria del carico di rete o del database.
Successivamente, isolate l'impatto sul database confrontando il conteggio totale delle esecuzioni delle istruzioni SQL prima e dopo le modifiche al codice. La generazione di un jdedebug.log per un campione rappresentativo di diverse migliaia di record rivela l'esatto calo delle letture fisiche delle tabelle. In un recente progetto che coinvolgeva una R42565 (Invoice Print) pesantemente personalizzata, la rifattorizzazione dell'I/O della tabella F41021 annidata in un fetch residente in memoria ha ridotto i round-trip al database da oltre un milione a meno di 15.000 per una singola esecuzione batch.
La velocità non deve andare a scapito della stabilità, in particolare quando si scambia l'I/O su disco con la cache JDE o grandi strutture di memoria. Monitorate l'utilizzo della CPU e l'impronta di memoria dell'Enterprise Server tramite top su Linux o Task Manager su Windows durante l'esecuzione. Una cache JDE gestita male che non chiama deallocateUserCache o non libera i puntatori nelle business function C personalizzate si manifesterà come una perdita di memoria, mandando infine in crash il processo kernel jdenet_kIl processo di sistema fondamentale di JD Edwards che gestisce le comunicazioni di rete e l'esecuzione dei processi sul server..
Quando queste metriche si allineano—riduzione delle istruzioni database, allocazione stabile della memoria ed esecuzione pulita del codice C—un esercizio di ottimizzazione riuscito produce tipicamente una riduzione dal 70% al 90% del tempo di esecuzione totale per i batch ad alto volume. Fondamentalmente, eseguite un confronto completo dei PDF e delle tabelle utilizzando uno strumento come PDF Diff per garantire che la logica ottimizzata produca output finanziari e operativi identici alla versione precedente.
Se la riduzione dell'IO di tabella nei vostri UBE ad alto volume ha evidenziato colli di bottiglia più ampi nel vostro parco codice personalizzato, gli articoli tecnici sulla gestione della memoria delle BSFN C e sull'integrazione delle viste SQL forniscono una guida architettonica più approfondita per ottimizzare le performance dell'ERP aziendale.