Sql: Aggiornamento o inserimento in una sola query

  
Quando si scrivono applicazioni che utilizzano un database per il salvataggio dei dati, è sempre importante tenere presente che la velocità è uno dei fattori più influenti per la buona riuscita del nostro lavoro. Bisogna infatti pensare che in ogni banca dati possono essere memorizzati milioni di record che, se analizzati e trattati, possono richiedere tempo e risorse che vengono sottratti ad altre attività che nello stesso momento girano sulla macchina in uso. Proprio per questo motivo quando si lavora su db sql è sempre preferibile demandare ogni tipo di attività al database stesso poiché la sua struttura ed i suoi strumenti sono programmati affinché le operazioni siano il meno dispendiose possibile.
Una delle attività più ricorrenti da effettuare su una serie di dati è il loro aggiornamento (se i dati sono presenti) o il loro inserimento (qualora essi non esistano ancora) all’interno del database in base ad una serie di variabili campione (ad esempio l’imput di un utente in una form). Questo lavoro richiede sicuramente un’estrazione di dati per effettuare un confronto ed un’analisi al fine di capire se eseguire un aggiornamento o un inserimento. Se volessimo analizzare le operazioni da eseguire con una serie di step, rappresentanti un algoritmo, essi si presenterebbero così:
APRO LA CONNESSIONE AL DB
CERCO I DATI NEL DB
SE I DATI SONO PRESENTI:
    AGGIORNA I DATI CON I NUOVI VALORI
ALTRIMENTI:
    INSERISCI I DATI NEL DB
CHIUDO LA CONNESSIONE AL DB
Come si può vedere, nonostante il codice sia il più minimale possibile, esso richiede una serie di passaggi che portano via una notevole quantità di tempo. Basti pensare che se il database in questione contiene 1 milione di record esso verrà (nella migliore delle ipotesi) “percorso” 2 volte (non necessariamente nella sua interezza) e ciò significa analizzare una grande mole di dati. Se a ciò aggiungiamo la complessità dei vari moduli dei diversi linguaggi di programmazione che dovrebbero aiutarci in questo lavoro allora capiamo quanto risparmiare secondi preziosi diventi fondamentale. 
A giungerci in aiuto in questo contesto arriva uno strumento sql davvero molto potente: ON DUPLICATE KEY. Esso ci permette di eseguire le operazioni appena viste sopra (aggiornamento o inserimento) in una sola query senza preoccuparci di estrazioni e confronti. Il suo funzionamento è molto semplice. Esso si prende in carico il compito di analizzare la presenza di una determinata chiave e nel caso essa sia presente aggiornarla altrimenti inserirla. La sintassi si presenta come segue (l’esempio è riferito ad un db MySql):
INSERT INTO tabella (chiave, campo1, campo2, …, campoN) VALUES (valchiave, val1, val2, …, valN) ON DUPLICATE KEY UPDATE campo1=val1, campo2=val2, …, campoN = valN
In pratica la query si occupa di cercare all’interno del db il record in base al valore della chiave primaria (nel nostro caso chiave) qualora esso sia presente verrà aggiornato con i valori della tupla che segue VALUES altrimenti verrà creata una nuova voce con i valori definiti dopo UPDATE. Si noti che nell’esempio che il valore di chiave nel caso di inserimento non è definito poiché il database conterrà una chiave con autoincremento ma qualora (per nostre scelte strutturali) la chiave deve essere definita manualmente la si potrà passare come un qualsiasi altro parametro. La query diventerebbe così:
INSERT INTO tabella (chiave, campo1, campo2, …, campoN) VALUES (valchiave, val1, val2, …, valN) ON DUPLICATE KEY UPDATE chiave=valchiave, campo1=val1, campo2=val2, …, campoN = valN
Grazie all’uso di ON DUPLICATE KEY i vecchi step dell’algoritmo diventano:
APRO LA CONNESSIONE AL DB

ESEGUO QUERY

CHIUDO LA CONNESSIONE AL DB
La scelta di questo strumento si è dimostrata appropriata in un test eseguito di persona. Si è visto, infatti, che confrontando i tempi di esecuzione di uno script python non ottimizzato con db mysql in locale popolato da 96000 record di prova, i due diversi algoritmi (con e senza ON DUPLICATE KEY) hanno portato una differenza di tempo di circa il 15%.
  

MySql : operatore BETWEEN

Nel post precedente abbiamo visto come sfruttare l’operatore IN di MySql per poter compattare il codice e renderlo sicuramente più veloce. Come detto l’operatore IN permette la selezione di un parametro tra una lista di possibili soluzioni candidate.

In questo post vedremo invece come effettuare una selezione in un range di valori mediante l’operatore BETWEEN. Immaginiamo di avere bisogno di selezionare da una tabella di utenti solo quelli che hanno un’altezza compresa tra 100 e 180 centimetri (ovvero 1 e 1.80 metri) per studiarne alcune composizioni statistiche. La query di selezione risulterebbe alquanto contorto se ci applicassimo la selezione usando gli operatori di comparazione di maggioranza e minoranza (“”). In tal caso il tutto si riduce ad una semplice query, abbastanza lineare del tipo:

SELECT * FROM ‘TabellaUtenti’ WHERE altezza BETWEEN 100 AND 180

L’uso di BETWEEN è sicuramente pratico quanto quello di IN e permette una soluzione stilistica decisamente migliore rispetto ad analoghi codici.

MySql : operatore IN

Semplificare le query utilizzate per un database è sicuramente una buona prassi per quanto riguarda lo stile di programmazione. Una query semplice è sinonimo di leggibilità e la leggibilità è sinonimo di apprendimento da parte di terzi del nostro codice. Nel mondo open source un codice chiaro avrà più possibilità di essere letto, capito ed, eventualmente, migliorato.

Quando si deve selezionare un dato, o una serie di dati , da un database di tipo MySql, che risponda ad un criterio tra diverse possibilità, si pensa immediatamente all’uso dell’operatore logico OR. In tal caso si avrà una query del tipo:

SELECT * FROM ‘tabella’ WHERE distro = ‘Debian’ OR distro = ‘Ubuntu’ OR distro = ‘Mint’

Tale soluzione è abbastanza prativa se si deve scegliere tra un numero ristretto di opzioni possibili. Quando le opzioni diventano molte allora si ricorre all’operatore IN. Esso ci permette di effettuare una scelta tra diverse opzioni usando una struttura simile ad una lista. In questo caso l’esempio precedente diviene:

SELECT * FROM ‘tabella’ WHERE distro IN (‘Debian’, ‘Ubuntu’, ‘Mint’)

La query ci ha sicuramente guadagnato in leggibilità e chiarezza e il nostro codice risulterà più chiaro anche per lunghe liste di opzioni tra le quali poter scegliere.