Vai al contenuto

SQL best practies

Se sei un programmatore, almeno una volta nella vita ti sarà capitato (o ti capiterà) di avere a che fare con un database e di conseguenza con le query SQL.

Potrebbe ad esempio capitare che il tuo codice venga consultato da altre persone, vuoi perchè lavori in team o perchè pubblichi i sorgenti su Github… Il problema è che non tutti riescono a scrivere correttamente, in modo ottimale, facilmente leggibile e con un’elevata velocità di elaborazione il codice SQL. In questo articolo vedremo alcune best practices utili per migliorare la leggibilità delle query SQL a vantaggio nostro e di tutti quelli che, per mille motivi, utilizzeranno il nostro codice. Se scrivi un codice “pulito” gli altri ti ringrazieranno.

Snake Case per schema, tabelle e colonne

Adotta uno stile unico di programmazione per il linguaggio SQL. Questo ti aiuterà moltissimo per mantenere il codice a lungo tempo. Esistono diversi stili di programmazione tra cui ricordiamo i più comuni:

  • camelCase
  • PascalCase
  • kebab-case (difficilmente utilizzato nei linguaggi di programmazione)
  • snake_case

Lo snake_case per il linguaggio SQL risulta essere, a mio parere, la soluzione ottimale per scrivere query.

Maiuscolo per le clausole

Quando formuli una query di selezione, inserimento o altro, dovresti sempre usare lettere maiuscole per le clausole SQL in quanto aiuterà te o chiunque legga il tuo codice a trovare facilmente quali operazioni/manipolazioni stai eseguendo. Anzichè scrivere cosi:

select id_ordine, numero from tb_ordini

puoi scrivere senz’altro cosi:

SELECT id_ordine, numero FROM tb_ordini

In questo modo a colpo d’occhio sapremo che si tratta di una query di selezione e quale tabella sta per essere interrogata.

Indentazione e/o la spaziatura

Avere una corretta indentazione del codice è molto importante perchè rende il codice pulito e quindi più facile da leggere per chiunque. Due regole da fissare in mente:

  1. Utilizza una riga per ogni colonna (nella SELECT)
  2. Scrivi un’istruzione per riga

Anzichè così:

SELECT colonnaB, FOO(colonna_c) FROM tabella_sinistra JOIN tabella_destra ON tabella_sinistra.colonnaA = tabella_destra.colonna WHERE espressione_filtro GROUP BY colonnaB HAVING espressione_filtro ORDER BY colonnaB ASC/DESC LIMIT ROW_COUNT;

dovremmo scrivere così:

SELECT 
   colonna_b, 
   FOO(colonna_c) 
FROM tabella_sinistra 
JOIN tabella_destra 
ON tabella_sinistra.colonna_a = tabella_destra.colonna_a 
WHERE espressione_filtro 
GROUP BY colonna_b 
HAVING espressione_filtro 
ORDER BY colonna_b ASC/DESC 
LIMIT ROW_COUNT;

In questo esempio sono stati applicati anche altre best practices e volutamente “corretti” i nomi di alcune colonne, in modo tale che la relazione JOIN sia ancora più chiara: utilizzano infatti lo stesso nome (colonna_a).

Alias

Gli alias vengono utilizzati per assegnare alle colonne un nome intuitivo definito dall’utente. Gli alias in SQL vengono creati utilizzando ‘AS’, seguito dal nome definito dall’utente.

Anzichè questo:

SELECT 
   order_id, 
   SUM(price)
FROM tab1 
INNER JOIN tab2 ON tab1.prod_id = tab2.prod_id 
GROUP BY order_id

potremmo usare degli alias sia per le funzioni, che per “accorciare” i nomi delle tabelle nei join, in questo modo:

SELECT 
   t1.order_id, 
   SUM(t1.price) AS sum_price
FROM tabella1 AS t1
INNER JOIN tabella2 AS t2 ON t1.prod_id = t2.prod_id 
GROUP BY t1.order_id

Nomi di tabelle intuitivi

There are only two hard things in Computer Science: cache invalidation and naming things. — Phil Karlton

Ebbene si, alcuni programmatori peccano di poca fantasia. Durante la fase di progettazione è importante scegliere dei nomi intuitivi alle tabelle e ai campi. Tali nomi dovrebbero rappresentare ciò che stai cercando di ottenere. Quando si lavora in team vale sempre la pena ritagliare del tempo per definire delle convenzioni comuni. Ma sopratutto, quando si sceglie un nome a una tabella o un campo, non usare mai un nome “temporaneo” che verrà cambiato in seguito, perchè probabilmente non lo cambierai più…

Una query poco intuitiva potrebbe essere la seguente:

CREATE TABLE table1 AS
SELECT data_ordine, 
   COUNT(id_ordine) 
FROM ordini
WHERE id_utente = 3 
GROUP BY data_ordine

Questa query, non fa altro che creare una nuova tabella chiamata table1 che prenda i dati direttamente da una SELECT filtrata. La query sopra potrebbe essere ottimizzata in questo modo:

CREATE TABLE ordini_filtrati AS
SELECT data_ordine, 
   COUNT(id_ordine) AS totale_ordini
FROM ordini
WHERE id_utente = 3 
GROUP BY data_ordine

Aggiungendo degli alias al posto giusto e una corretta nominazione della nuova tabella, la query risulta essere più comprensibile.

Commentare il codice

Commentare il codice è uno dei passaggi più importanti per rendere il codice leggibile e comprensibile. I commenti devono stare racchiusi tra /* */ e potrebbero seguire il seguente schema per descrivere gli aspetti dello sviluppo, senzaperò  dilungarsi troppo in chiacchiere (il nostro obiettivo è scrivere codice, non un tema d’italiano):

  1. L’obiettivo del codice
  2. Nome dell’autore
  3. Data
  4. Descrizione del codice
/* 
Obiettivo: ottenere l'importo dell'ordine corrispondente a ciascun ordine
Autore: Mario Rossi
Data: 05 maggio 2022 
Descrizione: questo codice fornisce l'id ordine e l'importo dell'ordine corrispondente unendo la tabella dettaglio_ordini e prodotti su id_prodotto (chiave primaria) 
*/ 

SELECT prodotti.id_ordine, SUM(dettaglio_ordine.prezzo) AS importo_ordine 
FROM table1 AS dettaglio_ordine
INNER JOIN table2 AS prodotti ON dettaglio_ordine.id_prodotto = prodotti.id_prodotto 
GROUP BY prodotti.id_ordine

Non abusare del carattere *

L’uso di SELECT * rende l’output un po’ una scatola nera in quanto nasconde le informazioni/colonne selezionate. L’uso dei nomi di colonna nella clausola SELECT è molto utile per capire quali colonne (o informazioni) stiamo selezionando per il nostro output. In molti casi l’utilizzo del carattere jolly * potrebbe rivelarsi controproducente, si pensi ad esempio a quelle tabelle strutturati con decine di campi, molti dei quali sono informazioni che non ci interessano ai fini della nostra SELECT oppure che contengono informazioni riservate.

Anzichè questo:

SELECT * FROM ordini

Utilizziamo questo in modo da definire al meglio l’interrogazione nonchè ottimizzare l’output:

SELECT 
   id_ordine,
   data_ordine,
   importo_totale
FROM ordini

SQL è fantastico e la sua flessibilità è un punto di forza ma può anche essere una trappola. Potresti non rendertene conto all’inizio, soprattutto se sei l’unico sviluppatore del progetto ma se a un certo punto, avessi la necessità di lavorare con un team o se qualcuno dovesse continuare il tuo lavoro, un codice SQL non ottimizzato senza una serie di best practice diventerà un peso.