Introduzione
Mentre molti server nostrani si ostinano a mantenere una versione 3.23.x, la MySQL AB (che come si può intuire è la società che sviluppa il noto RDBMS) ha rilasciato nel giro di un anno (Ottobre 2004 - Ottobre 2005) ben due major release del suo software di punta, mandando in pensione quelle precedenti. Per major release si intende una versione del software che introduce grosse novità (come ad esempio la versione 5 di PHP), e queste versioni di MySQL includono novità molto sostanziose.
Le novità
Analizziamo brevemente solo le caratteristiche più significative introdotte dalle varie versioni di mysql:
- La versione 4.0 ha introdotto le UNIONI (Unions) e il sistema di caching (che abbiamo già analizzato in un articolo precedente).
- La versione 4.1 ha introdotto le SUBQUERY, il supporto per OpenGIS, un maggior numero di
- storage engine (prima di questa versione erano supportati solo ISAM, MyISAM, INNODB), un supporto molto scalabile per la localizzazione.
- La versione 5.0 ha introdotto STORED PROCEDURES, VISTE (Views), Cursors, TRANSAZIONI (Transactions), TRIGGERS, ulteriori storage engine.
Insomma, anche se nato per essere un RDBMS veloce ma privo delle caratteristiche essenziali per un utilizzo slegato dall'ambito web, MySQL sta compiendo una rapida metamorfosi per portarsi su standard qualitativi più elevati non peggiorando per questo le sue prestazioni. Insomma, un database server che, mattone dopo mattone, cresce aggiungendo funzionalità.
Nel corso di questo articolo cercherò di illustrare con termini semplici cosa rappresentano in concreto queste novità e in quali ambiti è possibile sfruttarle senza però scendere in campo pratico. Questo aspetto senza dubbio molto importante verrà infatti trattato in articoli successivi.
Unioni (Unions)
Presenti dalla versione: 4.0, Manuale: http://dev.mysql.com/doc/refman/5.0/en/union.html
Il comando UNION, come il JOIN, serve a creare una relazione tra due tabelle. Se il comando JOIN univa i dati provenienti da due tabelle diverse in un unico record (con una somma quindi orizzontale) il comando UNION esegue un'unione diametralmente opposta permettendo di unire i due risultati come se provenissero da un'unica tabella (somma verticale).
Capita spesso di trovarsi di fronte a un database mal progettato in cui una stessa struttura si ripete in diverse tabelle. Con il comando UNION è possibile eseguire una query su queste tabelle sommando i risultati, proprio come se provenissero da un'unica tabella.
Questo comando agisce sempre come DISTINCT (seleziona cioè sempre record unici). Per poter selezionare anche i "doppioni" è necessario utilizzare UNION ALL.
Esempio:
Tabella Impiegati_Lombardia(ID, Nome, Cognome) 1 | Marco | Rossi 2 | Francesco | Verdi 3 | Alberto | Anastasi Tabella Impiegati_Toscana(ID, Nome, Cognome) 1 | Alberto | Franceschi 2 | Filippo | Fabbri 3 | Andrea | Federichi Query (SELECT Nome FROM Impiegati_Lombardia) UNION (SELECT Nome FROM Impiegati_Toscana) # Questa query seleziona solo 5 impiegati (ci sono due Alberto). # Utilizzando UNION ALL invece sarebbero stati estratti 6 record.
Subquery
Presenti dalla versione: 4.1, Manuale: http://dev.mysql.com/doc/refman/5.0/en/subqueries.html.
Si utilizzano le subquery ogni qual volta si voglia confrontare i valori contenuti in un recordset di una query con quelli di un altro. Nell'ambito web probabilmente questa è la caratteristica che più mancava a mysql e che imponeva l'utilizzo di complicate JOIN oppure di workaround eseguti nel linguaggio di programmazione con il quale ci si interfacciava a MySQL.
L'esempio più comune dell'utilizzo di una subquery è dato dal dover selezionare da una tabella solo i record che non rispettano una determinata relazione con una seconda:
SELECT colonne FROM tabella_1 WHERE valore_1 NOT IN (SELECT valore_2 FROM tabella_2)
Prima della versione 4.1 del RDBMS non era possibile eseguire questa query ed era invece necessario compiere questi passaggi da PHP:
- Selezionare tutti i valori del campo valore_2 dalla tabella tabella_2.
- Popolare un array con tutti questi valori.
- Eseguire una query in cui confrontare il campo valore_1 della tabella tabella_1 con tutti i valori dell'array popolato.
In alternativa era possibile sfruttare una LEFT JOIN (come descritto in questa pagina del manuale. Non vi è dubbio però che le subquery rendano di più facile comprensione l'intera query permettendoci più rapidi sviluppi e manutenzioni.
Nell'implementazione MySQL delle subquery esistono comunque delle limitazioni.
Stored Procedures
Presenti dalla versione: 5.0, Manuale: http://dev.mysql.com/doc/refman/5.0/en/stored-procedure-syntax.html
Iniziamo la carrellata delle nuove caratteristiche introdotte dalla versione 5.0 (che tra l'altro è la versione stabile raccomandata dalla MySQL AB) con le STORED PROCEDURES. Così come nei linguaggi di programmazione esistono vari metodi per scrivere una sola volta il codice da eseguire in diversi punti, così nel linguaggio sql è possibile stabilire a priori delle funzioni o procedure personalizzate.
Questo passaggio permette di:
- Rendere disponibile agli script che si interfacciano con il nostro database un set di API in modo da essere sicuri del funzionamento di una query su tutti i sistemi.
- Semplificare notevolmente le query attraverso l'uso di chiamate a funzioni personalizzate.
Esattamente come le funzioni dei linguaggi di programmazione, le stored procedures possono essere composte da valori in input, valori in output, tipi di valori (è necessaria la dichiarazione del tipo di variabile utilizzata), costrutti di controllo del flusso (if/then/else, case, cicli), passaggio di variabili per indice, chiamate ad altre funzioni personalizzate.
In MySQL le stored procedures devono essere dichiarate sempre tramite una query di tipo CREATE FUNCTION. Una volta dichiarata la funzione personale possiamo in ogni momento controllarne lo stato con SHOW FUNCTION STATUS oppure controllare la query che l'ha generata (in pratica il codice sorgente) con SHOW CREATE FUNCTION.
Se vogliamo modificare una funzione creata in precedenza possiamo usare ALTER FUNCTION e se infine decidiamo di eliminarla è necessario fare ricorso a DROP FUNCTION. Ovviamente è possibile eseguire questi comandi anche nel caso in cui quella che stiamo dichiarando non sia una funzione ma una procedura con i rispettivi comandi di CREATE PROCEDURE, SHOW PROCEDURE STATUS, SHOW CREATE PROCEDURE, ALTER PROCEDURE e DROP PROCEDURE. L'unica differenza tra funzioni e procedure sta nel fatto che le prime hanno un valore di ritorno mentre le seconde no.
Anche questa caratteristica del RDBMS presenta delle restrizioni.
Ritorneremo in seguito sulle procedure dato che saranno oggetto di un prossimo articolo.
Cursori (Cursors)
Presenti dalla versione: 5.0 Manuale: http://dev.mysql.com/doc/refman/5.0/en/cursors.html.
I cursori sono dei puntatori ai recordset di specifiche query utili da utilizzare soprattutto nell'ambito delle procedure personalizzate. Permettono di accedere a questi recordset e, tramite il comando FETCH assegnare i valori dei vari campi a specifiche variabili (un comportamento molto simile a quello che in PHP risulta essere il foreach).
Triggers
Presenti dalla versione: 5.0, Manuale: http://dev.mysql.com/doc/refman/5.0/en/triggers.html
Altra caratteristica molto interessante è rappresentata nel linguaggio SQL dai trigger. Tramite questi strumenti è possibile eseguire specifici comandi (ad esempio una procedura personalizzata) nel momento in cui vengono aggiornati (comando UPDATE), inseriti (comando INSERT) oppure eliminati (comando DELETE) i dati di una tabella.
Un esempio banale dell'utilizzo dei trigger potrebbe essere quello di mantenere i valori di un determinato campo sempre all'interno di un range di valori (esempio [0, 100]). Ogni volta che quel campo viene aggiornato si attiva un trigger che controlla il nuovo valore e, nel caso in cui esca dal range accettato lo sostituisce con un valore di default. In questo modo ci si trova sempre con un database efficiente e con dei dati "accettabili" senza dover replicare i controlli dal linguaggio di programmazione per tutte le query eseguite.
Viste (Views)
Presenti dalla versione: 5.0, Manuale: http://dev.mysql.com/doc/refman/5.0/en/views.html
è anche possibile da questa versione di MySQL creare delle viste sulle query. In questo modo è possibile creare quelle che a tutti gli effetti agiscono come delle tabelle temporanee già popolate. Il fatto interessante è rappresentato dalla complessità delle query che si possono eseguire: possono contenere funzioni o calcoli complessi. La vista permette di salvare i risultati di un recordset; in questo modo è possibile selezionare i risultati di operazioni dispendiose dal punto di vista prestazionale senza doverle rieseguire ogni volta. Sono molto utili soprattutto nel caso in cui il numero di SELECT sia molto superiore al numero di operazioni di scrittura sulla tabella.
Transazioni (Transactions)
Presenti dalla versione: 5.0, Manuale: http://dev.mysql.com/doc/refman/5.0/en/transactional-commands.html
Dalla versione 5.0 MySQL introduce anche il concetto di transazioni, anche se limitate alle sole tabelle di tipo InnoDB. Una transazione permette di portare a termine una serie di query solo se tutte quante vanno a buon fine. Nel caso in cui anche una sola delle query generi un errore, è possibile gestirlo per evitare errori nel database.
Le transazioni risultano essere molto utili ad esempio in complicate fasi di INSERT multiple in cui le insert successive dipendono da quelle precedenti: non bisogna gestire i vari errori dal linguaggio di programmazione e si è sicuri di non avere incongruenze nel database.
Anche le transizioni saranno oggetto di un articolo più tecnico e approfondito in futuro.
Conclusioni
E nel futuro? È a buon punto anche lo sviluppo della versione 5.1 di MySQL che verrà rilasciata come beta a breve. Tra le caratteristiche più interessanti di questa ennesima versione troveremo probabilmente il supporto per le FOREIGN KEYS (gli indici esterni) esteso ai vari tipi di tabelle e non più solo alle InnoDB.