Introduzione
Lo sviluppo di applicazioni JDBC mirate all'ottimizzazione
delle prestazioni non è semplice. I driver JDBC
non lanciano alcuna eccezione per segnalare quando il
codice in esecuzione è tropo lento.
La
seguente serie di indicazioni relative alle prestazioni
presenta alcune linee guida di valenza generale per
il miglioramento dell'efficienza di un'applicazioni
JDBC, la cui stesura è stata realizzata a seguito
dell'esame di numerose implementazioni di applicazioni
JDBC correntemente rilasciate. Queste linee guida includono:
- Utilizzo
appropriato dei metodi per database che sfruttano
i metadata
- Recupero
dei soli dati richiesti
- Selezione
di funzioni che ottimizzano le prestazioni
- Gestione
delle connessioni e degli aggiornamenti
L'attenersi
a queste regole generali aiuta la risoluzione di alcuni
problemi comuni di prestazione dei sistemi JDBC.
Utilizzo
dei metodi per database che sfruttano i metadata
Poiché i metodi per database che fanno uso dei
metadata e che generano oggetti del ResultSet sono lenti
rispetto ad altri metodi JDBC, il loro utilizzo frequente
può deteriorare le prestazioni del sistema.
Minimizzazione
dell'utilizzo dei metodi per database che sfruttano
i metadata
Confrontati con altri metodi JDBC, i metodi per database
che fanno uso dei metadata e che generano oggetti del
ResultSet sono relativamente lenti. Per evitare la necessità
di esecuzioni multiple, le applicazioni dovrebbero conservare
nelle memoria cache informazioni restituite dai set
dei risultati che generano i metodi per database basati
sui metadata.
Anche
se quasi nessuna applicazione JDBC può essere
scritta senza utilizzare metodi facenti uso dei metadata,
le prestazioni del sistema possono essere migliorate
minimizzando il ricorso a tali metodi. Per restituire
tutte le informazioni delle colonne di risultati richieste
dalle specifiche JDBC, un driver JSP può trovarsi
a dovere eseguire query complesse o multiple per ritornare
il set dei risultati necessario per una singola chiamata
a un metodo per database che sfrutti i metadata. Questi
elementi particolari del linguaggio SQL sono costosi
dal punto di vista delle prestazioni.
Le
applicazioni dovrebbero conservare nelle memoria cache
informazioni provenienti dai metodi facenti uso dei
metadata. Per esempio, si chiami una volta getTypeInfo
nell'applicazione e si mantengano memorizzati a parte
gli elementi dai quali dipende la propria applicazione.
E' improbabile che un'applicazione faccia uso di tutti
gli elementi del set dei risultati generato da un metodo
per database basato su metadata, perciò non dovrebbe
essere difficile conservare le informazioni nella memoria
di cache.
Evitare
pattern di ricerca
L'utilizzo di argomenti nulli o pattern di ricerca in
metodi per database facenti uso di metadata, determina
la generazione di query che consumano tempo. In aggiunta,
il traffico di rete cresce potenzialmente a causa dei
risultati indesiderati. Si deve quindi cercare sempre
di fornire il maggior numero possibile di argomenti
non nulli ai set dei risultati che generano metodi per
database basati su metadata.
Essendo
i metodi di tale tipo lenti, le applicazioni dovrebbero
invocarli nel modo più efficiente possibile.
Molte applicazioni passano solo argomenti non nulli
nel numero minimo necessario per il successo della chiamata
alla funzione.
Per
esempio:
ResultSet
WSrs = WSc.getTables (null, null, "WSTable",
null);
dovrebbe
essere:
ResultSet
WSrs = WSc.getTables ("cat1", "johng",
"WSTable","TABLE");
Nella
prima chiamata a getTable(), l'applicazione probabilmente
vuole sapere se la tabella WSTable esiste. Un driver
JDBC, naturalmente, considera la chiamata in modo "letterale"
e interpreta la richiesta in diversamente. Un driver
JDBC interpreta la richiesta come segue: restituisci
tutte le tabelle, le view, le tabelle di sistema, i
sinonimi, le tabelle temporanee o gli alias che esistono
in ogni schema di database, all'interno di ogni catalogo
di database, che siano denominati 'WSTable'.
La
seconda chiamata a getTable() rispecchia più
accuratamente ciò che l'applicazione vuole fare.
Un driver JDBC interpreta tale richiesta nel modo seguente:
restituisce tutte le tabelle esistenti nello schema
'johng' del presente catalogo il cui nome sia 'WSTable".
E'
evidente che un driver JDBC può elaborare la
seconda richiesta in modo assai più efficiente
di quanto non possa fare con la prima.
Spesso,
si dispone di pochi DATI relativamente all'oggetto su
cui si stanno chiedendo informazioni. Qualsiasi informazione
che l'applicazione può inviare al driver, mentre
chiama metodi facenti uso di metadata, può indurre
un miglioramento sia delle prestazioni che dell'affidabilità.
Utilizzo
di dummy query per determinare le caratteristiche delle
tabelle
Si eviti l'uso di getColumns() per determinare le caratteristiche
relative ad una tabella. Si utilizzi invece una dummy
query con getmetadata().
Si
consideri un'applicazione che permette all'utilizzatore
di scegliere le colonne che saranno selezionate. Sarebbe
conveniente per l'applicazione utilizzare getColumns()
per fornire all'utente informazioni sulle colonne o
dovrebbe, piuttosto, preparare una dummy query e chiamare
getmetadata()?
Caso
1: Metodo getColumns
ResultSet
WSrc = WSc.getColumns (... "UnknownTable"
...);
// This call to getColumns() will generate a query to
// the system catalogs... possibly a join
// which must be prepared, executed, and produce
// a set dei risultati
. . .
WSrc.next();
string Cname = getString(4);
. . .
// user must retrieve N rows from the server
// N = # result columns of UnknownTable
// result column information has now been obtained
Caso
2: Metodo getmetadata
//
prepare dummy query
PreparedStatement WSps = WSc.prepareStatement
("SELECT * from UnknownTable WHERE 1 = 0");
// query is never executed on the server - only prepared
ResultSetmetadata WSsmd=WSps.getmetadata();
int numcols = WSrsmd.getColumnCount();
...
int ctype = WSrsmd.getColumnType(n)
...
// result column information has now been obtained
In
entrambi i casi, viene inviata una query al server.
Ma nel Caso 1 deve essere preparata ed eseguita la query,
deve essere formulata la descrizione delle informazioni
risultanti, e deve essere mandato al client un set dei
risultati di righe. Nel Caso 2 invece è unicamente
necessario che venga preparata una semplice query e
venga formulata la descrizione delle informazioni risultanti.
E' palese che il Caso 2 è un modello che presenta
prestazioni migliori.
Per
complicare un poco questa discussione, si consideri
un server DBMS che di per sé non supporti la
generazione di un comando SQL. Le prestazioni nel Caso
1 non mutano, mentre nel Caso 2 migliorano leggermente,
poiché la dummy query deve essere valutata invece
che solo preparata. Dato che l'istruzione 'Where close'
dà sempre il valore FALSE, la query non fornisce
come risultato alcuna riga e dovrebbe effettuare l'esecuzione
senza accedere a dati della tabella. Per questa ragione
il secondo metodo supera in prestazioni il primo.
Riassumendo,
vanno utilizzati sempre metadata del set dei risultati
per ricercare informazioni relative alle colonne della
tabella quali i nomi di colonna, i tipi di dati di colonna,
la precisione e la scala di colonna. E' opportuno l'uso
di getColumns() quando le informazioni richieste non
possono essere ottenute da metadata del set dei risultati
(cioè per i valori di default delle colonne della
tabella).
Cercate,
nel numero del prossimo mese, ulteriori suggerimenti
sulle prestazioni, in particolare sul 'Ricupero dei
soli dati richiesti'.
L'articolo
è stato originariamente pubblicato su TheServerSide.com
|