Omet navegació

6.5 - Millora de rendiment

Un altre aspecte important que mesura la qualitat de les aplicacions és l’eficiència amb la qual s’aconsegueix comunicar amb el SGBD. Per optimitzar la connexió és important reconèixer quins processos poden actuar de coll d’ampolla.

En primer lloc, analitzarem la petició de connexió a un SGBD perquè es tracta d’un procés costós però inevitable que cal considerar.

En segon lloc, estudiarem les sentències predefinides, perquè el seu ús facilita la creació de dades clau i índexs temporals de manera que siga possible anticipar-se a la demanda o disposar de les dades de forma molt més ràpida.

Temps de vida d'una connexió

L’establiment d’una connexió és un procediment molt lent, tant a la part client com a la part servidor.

  • A la part client, DriverManager ha de descobrir el controlador correcte d’entre tots els que haja de gestionar. La majoria de vegades les aplicacions treballaran només amb un únic controlador, però cal tenir en compte que DriverManager no coneix a priori quina URL de connexió correspon a cada controlador, i per saber-ho envia una petició de connexió a cada controlador que tinga registrat, el controlador que no li retorna error serà el correcte.
  • A la banda servidor, es crearà un context específic i s’habilitaran un conjunt de recursos per cada client connectat. És a dir, que durant la petició de connexió el SGDB ha de gastar un temps considerable abans de deixar operativa la comunicació client-servidor.

Aquesta elevat cost de temps concentrat en el moment de la petició de connexió fa que ens plantegem si val la pena obrir i tancar la connexió cada vegada que ens toque executar una sentència SQL, o obrir una connexió al principi de l'aplicació que tancaríem en finalitzar. Lamentablement no hi ha una única resposta, sinó que depèn de la freqüència d’ús de la connexió i el número de connexions contra el mateix SGBD.

Com en tot, es tracta de trobar el punt d’equilibri. Si el número de clients, i per tant de connexions, és baix i la freqüència d’ús és alta, serà preferible mantenir les connexions obertes molt de temps. Per contra, si el número de connexions és molt alt i la freqüència d'ús baixa, el que serà preferible serà obrir i tancar la connexió cada vegada que es necessite. I també hi haurà una multitud de casos en què la solució consistirà a mantenir les connexions obertes però no permanentment. Es pot donar un temps de vida a cada connexió, o bé tancar-les després de restar inactiva una quantitat determinada de temps, o es pot fer servir el criteri de mantenir un número màxim de connexions obertes, tancant les més antigues o les més inactives quan se sobrepasse el límit.

Sentències predefinides

JDBC disposa d’un objecte derivat del Statement que s’anomena PreparedStatement., a la qual se li passa la sentència SQL en el moment de crear-lo, no en el moment d'executar la sentència (com passava amb Statement). I a més aquesta sentència pot admetre paràmetres, cosa que ens pot anar molt bé en determinades ocasions.

Siga com siga, PreparedStatement presenta avantatges sobre el seu antecessor Statement quan ens toque treballar amb sentències que s'hagen d'executar diverses vegades. La raó és que qualsevol sentència SQL, quan s’envia al SGBD serà compilada abans de ser executada.

  • Utilitzant un objecte Statement, cada vegada que fem una execució d’una sentència, ja siga via executeUpdate o bé via executeQuery, el SGBD la compilarà, ja que li arribarà en forma de cadena de caràcters.
  • En canvi, al PreparedStament la sentència mai varia i per tant es pot compilar i guardar dins del mateix objecte, de manera que les següents vegades que s’execute no caldrà compilar-la. Això reduirà sensiblement el temps d’execució.

En alguns sistemes gestors, a més, fer servir PreparedStatements pot arribar a suposar més avantatges, ja que utilitzen la seqüència de bytes de la sentència per detectar si es tracta d’una sentència nova o ja s’ha servit amb anterioritat. D’aquesta manera es propicia que el sistema guarde les respostes en la memòria caché, de manera que es puguen lliurar de forma més ràpida.

La principal diferència dels objectes PreparedStatement en relació als Statement, és que en els primers se'ls passa la sentència SQL predefinida en el moment de crear-lo. Com que la sentència queda predefinida, ni els mètodes executeUpdate ni executeQuery requeriran cap paràmetre. És a dir, justet al revès que en el Statement.

   ...
sentenciaSQL = "INSERT INTO PAIS VALUES('Marroc')";
PreparedStatement stm = con.prepareStatement(sentenciaSql);
stm.executeUpdate();
   ...

Els paràmetres de la sentència es marcaran amb el símbol d’interrogant (?) i s’identificaran per la posició que ocupen a la sentència, començant a comptar des de l’esquerra i a partir del número 1. El valor dels paràmetres s’assignarà fent servir el mètode específic, d’acord amb el tipus de dades a assignar. El nom camençarà per set i continuarà amb el nom del tipus de dades (exemples: setString, setInt, setLong, setBoolean…). Tots aquestos mètodes segueixen la mateixa sintaxi:

setXXXX(<posicioALaSentenciaSQL>, <valor>);

Veiem un exemple, en el qual suposem que tenim les dades a introduir en un objecte article:

...
PreparedStatement st = con.prepareStatement("INSERT INTO ARTICLE (id, descripcio) VALUES(?, ?)");
st.setLong(1, article.getId());
st.setString(2, article.getDescripcio());
st.executeUpdate();
...