Migliorare le Prestazioni delle Applicazioni Gestionali

I problemi che possono affliggere un’applicazione gestionale non sono di solito sintomi isolati, bensì il frutto di un progetto non ben realizzato. L’attività di miglioramento delle prestazioni deve pertanto basarsi sull’individuazione dei difetti di progettazione che sono la causa del deperimento delle prestazioni. Esistono due approcci al miglioramento ( tuning ) delle prestazioni di un software gestionale. L’approccio proattivo che consiste nell’analizzare le prestazioni in tutto il ciclo di produzione del programma, partendo dall’analisi e l’approccio reattivo quando si rende necessaria l’ottimizzazione per problemi di performance.
Per il miglioramento delle prestazioni del software gestionale, un’azienda deve assoggettarsi a dei costi, che sono molto contenuti nelle fasi iniziali del progetto e quindi un approccio proattivo, mentre effettuando i test in una fase avanzata di sviluppo i costi aumentano ed i benefici diminuiscono. Da questa analisi quindi, un approccio proattivo è da preferire a quello reattivo.
Le attività di ottimizzazione si focalizzano sul progetto dell’applicazione, sull’utilizzo del linguaggio SQL, sulla manipolazione e memorizzazione dei dati, sul traffico di rete e sull’occupazione della memoria. Di solito non è una sola persona che si fa carico di queste operazioni, ma il responsabile del progetto, che deve tenere sotto controllo le attività dell’analista, del progettista ed del programmatore. Il miglioramento delle prestazioni dovute alla gestione del database comportano diversi passaggi da effettuare. Una rigida aderenza alle regole di progettazione degli archivi relazionali ed una cattiva stesura degli stessi possono causare decadimento delle prestazioni da parte di tutta l’applicazione gestionale. Le tabelle realizzate secondo i dettami della terza forma normale, tendono a sfruttare al meglio lo spazio su disco, ma possono implicare l’aumento nel numero di accessi I/O al dispositivo, pertanto richiedere uno sforzo maggiore da parte del database. Un modo per ridurre il tempo di elaborazione delle query consiste nell’effettuare la denormalizzazione di alcune tabelle durante la fase di passaggio dal progetto logico a quello fisico. Per migliorare i tempi di ricerca, a discapito di maggiori informazioni inserite nel database, si fa uso di indici e questo comporta che ogni volta che si inserisce un record si debba necessariamente inserire un indice di quel dato, così anche nelle eliminazioni, per giunta, non deallocando lo spazio precedentemente occupato. Un eccessivo proliferare di indici comporta quindi un inesorabile rallentamento delle operazioni di scrittura e un maggior numero di ricerche, che possono andare a vanificare i benefici offerti dagli indici. La cattiva progettazione degli indici comporta un notevole decadimento delle prestazioni, tuttavia porvi rimedio è semplice, poiché serve soltanto intervenire sul database e non sull’applicazione. Ci sono dei casi in cui, ad esempio, gli indici associati ad una colonna non siano utilizzati. Prendiamo ad esempio il caso dei Clienti, se abbiamo un indice I_Clienti ed i campi in questo ordine: Nome, Cognome, Codice_Fiscale, quando effettuiamo la query SELECT * FROM clienti WHERE Cognome = ‘Rossi’, questa ignorerà l’indice, poiché nella clausola WHERE non compare il Cognome. Un ottimo approccio sarebbe quello di vedere le funzioni dell’applicazione che utilizzano gli indici e poi crearli all’interno del database, in modo da razionalizzare il tutto ed avere i tempi di risposta delle query nella base dati. Oltre agli indici normali possiamo anche utilizzare i Clustered Hashed, che hanno la caratteristica di velocizzare notevolmente le query di equivalenza. E’ necessario definire gli indici clustered su tabelle vuote e quindi queste vanno svuotate e riempite nuovamente dei dati. Ci sono dei casi poi, in cui l’uso degli indici è controproducente, infatti Kevin Loney, che studia i database Oracle, afferma che su tabelle con oltre 10 milioni di record e con estrazioni dell’1% del contenuto, è preferibile non utilizzare affatto gli indici. Un altro tipo di ottimizzazione che possiamo ottenere sul database è la possibilità di immagazzinare le informazioni provenienti da operazioni fatte per un altro utente, quindi lasciare i dati in un’area per attendere una nuova elaborazione degli stessi, in questo modo si andrebbero a migliorare notevolmente le prestazioni del software gestionale. Per fare in modo che il lavoro delle query ricada sul DBMS possiamo utilizzare le Stored Procedure, che sono delle funzioni compilate sul database. Il ricorso a queste funzioni deve essere bilanciato dal fatto che esse caricano di lavoro il nostro server e con l’aumentare degli utenti i benefici si andrebbero ad annullare, ecco allora che occorre scaricare il lavoro su più macchine con la razionalizzazione del database.
Per quanto riguarda l’ottimizzazione del codice dell’applicazione, occorre prestare molta più attenzione per non incorrere nei cosiddetti errori di regressione, quelli cioè nati dopo il tuning del codice. E’ buona norma effettuare gli stessi test ad ogni cambiamento del codice. Un aspetto importante che occorre prendere in considerazione in questo caso è il tempo di attesa delle varie funzioni per l’accesso ai dati. Difatti quando un’applicazione utilizza una tabella, inserisce un lock che mette in attesa gli altri thread dell’applicazione o altri processi. Il metodo migliore è quindi diminuire i tempi di elaborazione dei carichi del database per impedire tempi di attesa lunghi. Prendiamo ad esempio il join, ogni volta che un DBMS deve fare il join di due tabelle, crea due tabelle temporaneee e poi confronta i record, un buon approccio è quello di diminuire il numero delle tabelle legate da join, al massimo è consigliabile inserirne tre, se poi c’é la necessità di inserirne di più, allora abbiamo un problema di progettazione dell’applicazione gestionale. Un altro problema da affrontare è il caricamento di dati statici in memoria, oggi con le quantità di RAM che abbiamo a disposizione è preferibile inserire in memoria i dati di tabelle utilizzate maggiormente, in modo da non costringere il database a continue compilazioni ed estrazioni. Se ad esempio facciamo dei loop su dei dati come i codici di avviamento postali, è preferibile far attendere più tempo nel momento del caricamento dell’applicazione che successivamente, ovviamente tutto deve essere ponderato e fare un’analisi dell’uso di detti dati ed il tempo di risposta del caricamento. Per un database l’operazione che impiega più tempo è la DELETE, infatti per sicurezza tale istruzione deve duplicare i dati da eliminare nel roll back segment, poi li marca come eliminati ed alla fine esegue il COMMIT.
In questo articolo abbiamo dato solo una piccola occhiata al mondo delle ottimizzazioni delle applicazioni che fanno uso di database. Le considerazioni dovranno essere certamente calate nelle diverse realtà tecnologiche ed organizzative, pur rappresentando un ottimo punto di partenza per il tuning delle applicazioni gestionali.

Di Giampaolo Rossi

Sviluppatore software da oltre 16 anni.