Lezione 4 — Tipi di dato MySQL: Guida Completa alla Scelta del Tipo Giusto

Scopri come scegliere correttamente i tipi di dato in MySQL per ottimizzare le prestazioni, risparmiare spazio e garantire l'integrità dei tuoi dati.

Introduzione ai Tipi di Dato in MySQL

Benvenuti alla quarta lezione del nostro corso "Impara MySQL in 45 lezioni". Dopo aver compreso cos'è un database e come creare le prime tabelle, è fondamentale affrontare uno degli aspetti più critici della progettazione di un database: la scelta dei tipi di dato.

In MySQL, ogni colonna di una tabella deve avere un tipo di dato definito. Ma perché è così importante? Molti principianti tendono a usare tipi di dato generici (come TEXT per tutto o VARCHAR(255) per ogni stringa), pensando che ciò semplifichi il lavoro. In realtà, questa è una pratica errata che porta a tre problemi principali:

  1. Performance: I tipi di dato più specifici permettono a MySQL di indicizzare i dati in modo più efficiente e di eseguire le query più velocemente.
  2. Spazio di archiviazione: Un INT occupa meno spazio di un VARCHAR che contiene un numero. Su milioni di righe, questa differenza può tradursi in gigabyte di spazio risparmiato.
  3. Integrità dei dati: Definendo un tipo DATE per una data, impedisci che un utente inserisca accidentalmente una stringa come "Gennaio" dove dovrebbe esserci un formato standard YYYY-MM-DD.

In questa lezione esploreremo le categorie principali di tipi di dato: Numerici, Stringhe, Date e Tempo.

1. Tipi di Dato Numerici

I tipi numerici si dividono principalmente in numeri interi e numeri decimali. La scelta dipende dalla natura del dato che devi memorizzare.

Numeri Interi (Integers)

Gli interi sono utilizzati per contatori, ID (chiavi primarie) e quantità discrete. MySQL offre diverse varianti a seconda della dimensione del numero che prevedi di memorizzare:

  • TINYINT: Molto piccolo. Ideale per valori booleani (0 o 1) o piccoli stati (es. status di un ordine).
  • SMALLINT: Per numeri leggermente più grandi.
  • MEDIUMINT: Una via di mezzo.
  • INT: Il tipo più comune per gli ID delle tabelle.
  • BIGINT: Fondamentale per applicazioni su scala globale (es. ID di post di un social network) dove il numero di record potrebbe superare i 2 miliardi.

Numeri Decimali e Virgola Mobile

Quando devi gestire prezzi, coordinate geografiche o misurazioni scientifiche, hai tre opzioni:

  • DECIMAL(p, s): È il tipo "fisso". p rappresenta la precisione totale e s le cifre decimali. Usa sempre DECIMAL per i soldi. Perché? Perché evita gli errori di arrotondamento tipici della virgola mobile.
  • FLOAT: Precisione singola. Utile per dati scientifici dove un piccolo errore di approssimazione non è crite.
  • DOUBLE: Precisione doppia. Più accurato del FLOAT ma occupa più spazio.

Ecco un esempio di creazione di una tabella che utilizza diversi tipi numerici:

CREATE TABLE prodotti (
    id INT AUTO_INCREMENT PRIMARY KEY, -- ID univoco per ogni prodotto
    nome VARCHAR(100) NOT NULL,
    prezzo DECIMAL(10, 2) NOT NULL, -- Massimo 10 cifre totali, 2 decimali (es. 99999999.99)
    quantita_magazzino SMALLINT UNSIGNED, -- UNSIGNED impedisce valori negativi
    valutazione_media FLOAT(3, 2) -- Esempio: 4.55
);

In questo codice, abbiamo usato DECIMAL per il prezzo per garantire che i calcoli finanziari siano esatti al centesimo. Abbiamo usato UNSIGNED per la quantità perché non può esistere un numero negativo di prodotti in magazzino.

2. Tipi di Dato per Stringhe

Le stringhe sono probabilmente i tipi di dato più utilizzati. La sfida qui è bilanciare la flessibilità con l'efficienza.

CHAR vs VARCHAR

Questa è la domanda classica per ogni principiante. Qual è la differenza?

  • CHAR(n): È a lunghezza fissa. Se definisci CHAR(5) e inserisci "Ciao" (4 caratteri), MySQL aggiungerà uno spazio vuoto per completare i 5. È più veloce per dati di lunghezza costante (es. codici fiscali, sigle di nazioni come 'IT', 'US').
  • VARCHAR(n): È a lunghezza variabile. Se definisci VARCHAR(255) ma inserisci "Ciao", MySQL occuperà solo lo spazio necessario per quei 4 caratteri (più un byte di controllo). È ideale per nomi, indirizzi ed email.

Tipi per Testi Lunghi

Quando VARCHAR non basta (il limite massimo è 65,535 byte), passiamo ai tipi TEXT:

  • TINYTEXT: Fino a 255 caratteri.
  • TEXT: Fino a 65,535 caratteri. Ideale per descrizioni di prodotti o commenti.
  • MEDIUMTEXT: Fino a 16 MB.
  • LONGTEXT: Fino a 4 GB. Usato per interi articoli di blog o log di sistema molto vasti.

Tipi Speciali: ENUM e SET

  • ENUM: Permette di scegliere un valore da una lista predefinita. Ad esempio: ENUM('Piccolo', 'Medio', 'Grande'). È molto efficiente perché internamente MySQL salva un numero, non la stringa.
  • SET: Simile a ENUM, ma permette di scegliere più valori dalla lista.

3. Tipi di Dato per Date e Ora

Gestire il tempo in un database è fondamentale per i log, le scadenze e l'analisi dei dati. MySQL offre diverse opzioni:

  • DATE: Formato YYYY-MM-DD. Usalo per le date di nascita o date di scadenza dove l'ora non è rilevante.
  • DATETIME: Formato YYYY-MM-DD HH:MM:SS. Registra un punto preciso nel tempo.
  • TIMESTAMP: Simile a DATETIME, ma è legato al fuso orario (UTC). Viene spesso usato per le colonne created_at e updated_at perché può aggiornarsi automaticamente.
  • TIME: Formato HH:MM:SS. Usato per durate o orari specifici.
  • YEAR: Memorizza solo l'anno in formato a 4 cifre.

Vediamo come implementare questi tipi in una tabella di ordini:

CREATE TABLE ordini (
    ordine_id INT AUTO_INCREMENT PRIMARY KEY,
    cliente_id INT,
    data_ordine DATE NOT NULL, -- Solo la data
    ora_consegna TIME, -- Solo l'orario
    creato_il TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Automatico al momento dell'inserimento
    aggiornato_il TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

In questo esempio, l'uso di CURRENT_TIMESTAMP permette al database di gestire autonomamente la data di creazione e l'ultimo aggiornamento senza che l'applicazione debba inviare questi dati manualmente.

4. Esempi Pratici: Casi d'Uso Reali

Per mettere in pratica quanto appreso, analizziamo tre scenari comuni di sviluppo web.

Caso A: Profilo Utente

Immaginiamo di creare un profilo utente per un social network. Quali tipi sceglieremmo?

  • Username: VARCHAR(30) (Lunghezza variabile, limite ragionevole).
  • Email: VARCHAR(255) (Standard per email).
  • Password: VARCHAR(255) (Le password hashate sono lunghe).
  • Data di Nascita: DATE.
  • Genere: ENUM('Maschio', 'Femmina', 'Altro', 'Preferisco non dire').
  • Bio: TEXT (L'utente può scrivere molto).

Caso B: E-commerce (Carrello)

  • ID Prodotto: INT UNSIGNED.
  • Quantità: TINYINT UNSIGNED (Raramente un utente compra più di 127 pezzi dello stesso oggetto).
  • Prezzo Unitario: DECIMAL(10, 2).

Caso C: Sistema di Log di Errore

  • ID Errore: BIGINT UNSIGNED (I log crescono velocemente, INT potrebbe esaurirsi).
  • Livello Errore: ENUM('INFO', 'WARNING', 'ERROR', 'CRITICAL').
  • Messaggio Errore: TEXT.
  • Data Ora: TIMESTAMP.

5. Errori Comuni da Evitare

Durante la mia esperienza come sviluppatore, ho visto molti principianti cadere in queste trappole:

1. Usare VARCHAR per i numeri

Errore: Salvare l'età o il prezzo come VARCHAR. Perché è sbagliato: Non puoi eseguire operazioni matematiche efficienti (SUM, AVG) direttamente nel database e l'ordinamento sarà alfabetico (es. "10" verrà prima di "2").

2. Usare TEXT per ogni stringa

Errore: Usare TEXT invece di VARCHAR per i nomi. Perché è sbagliato: I campi TEXT sono memorizzati fuori dalla tabella principale, il che rende l'accesso leggermente più lento e impedisce l'uso di valori di default in alcune versioni di MySQL.

3. Dimenticare l'UNSIGNED

Errore: Usare INT per l'ID di un utente. Perché è sbagliato: Un INT standard permette numeri negativi. Poiché un ID non sarà mai -5, usare INT UNSIGNED raddoppia virtualmente la capacità di memorizzazione dei numeri positivi.

4. Confondere DATETIME e TIMESTAMP

Errore: Usare TIMESTAMP per date molto lontane nel futuro (es. anno 2100). Perché è sbagliato: Il tipo TIMESTAMP ha un limite massimo (l'anno 2038). Per date che superano tale limite, è obbligatorio usare DATETIME.

6. Tabella Riassuntiva per il Riferimento Rapido

Per aiutarti a scegliere, ecco uno schema sintetico:

Tipo Dato Quando usarlo Esempio
TINYINT Booleani, stati piccoli is_active (0/1)
INT ID, contatori standard user_id
BIGINT ID massivi, numeri enormi tweet_id
DECIMAL Denaro, precisione esatta price (10.50)
VARCHAR Testi di lunghezza variabile email, name
CHAR Testi di lunghezza fissa country_code ('IT')
TEXT Descrizioni, articoli blog_content
DATE Date senza orario birth_date
TIMESTAMP Log, date di sistema created_at

Prossimi Passi

Ora che conosci i tipi di dato, sei in grado di progettare tabelle efficienti e robuste. Ma come facciamo a collegare queste tabelle tra loro? Un database non è fatto di tabelle isolate, ma di relazioni.

Nella Lezione 5, studieremo le Chiavi Primarie (Primary Keys) e le Chiavi Esterne (Foreign Keys). Impareremo come creare legami tra le tabelle (ad esempio, collegare un ordine a un utente specifico) per evitare la ridondanza dei dati e mantenere l'integrità del sistema.

Esercizio consigliato: Prova a progettare lo schema di un database per una piccola biblioteca. Quali tipi di dato useresti per il titolo del libro, l'ISBN, l'autore, la data di pubblicazione e lo stato di disponibilità? Scrivi il codice SQL e prova a eseguirlo nel tuo ambiente di sviluppo!