Introduzione ai Tipi di Dato Numerici in MySQL
Quando si progetta un database per un'applicazione web, una delle decisioni più critiche che uno sviluppatore deve prendere riguarda la scelta dei tipi di dato per le colonne che memorizzano numeri interi. In MySQL, le opzioni più comuni sono INT (Integer) e BIGINT.
Potrebbe sembrare una scelta banale: "Perché non usare sempre BIGINT per essere sicuri di non esaurire lo spazio?". Tuttavia, nel mondo dei database professionali, ogni byte conta. La scelta tra un intero standard e un intero a 64 bit influisce non solo sullo spazio di archiviazione su disco, ma anche sull'utilizzo della memoria RAM durante le operazioni di indicizzazione e sulle performance complessive delle query.
In questa guida approfondita, analizzeremo nel dettaglio cosa sono INT e BIGINT, come funzionano a livello di memoria e quali sono i criteri per scegliere il tipo di dato più adatto al tuo caso d'uso.
Cos'è l'INT (Integer) in MySQL?
Il tipo di dato INT è lo standard per la memorizzazione di numeri interi in MySQL. Occupa 4 byte (32 bit) di spazio fisico. Questa limitazione tecnica definisce l'intervallo di valori che una colonna di tipo INT può contenere.
Intervalli di Valore
Un INT può essere definito come Signed (con segno) o Unsigned (senza segno):
- Signed INT: Può memorizzare valori da -2,147,483,648 a 2,147,483,647.
- Unsigned INT: Poiché non deve gestire i numeri negativi, l'intervallo si sposta verso l'alto, andando da 0 a 4,294,967,295.
Quando usare INT
L'INT è perfetto per la maggior parte delle applicazioni web standard. Esempi tipici includono:
- ID di prodotti in un catalogo di medie dimensioni.
- Conteggi di visualizzazioni di un articolo (se non prevedi miliardi di visite).
- Identificativi di categorie o tag.
- Età di un utente o numeri di telefono (se trattati come interi, sebbene per i telefoni sia consigliato il VARCHAR).
Cos'è il BIGINT in MySQL?
Il BIGINT è, come suggerisce il nome, un intero "grande". Occupa 8 byte (64 bit), esattamente il doppio di un INT. Questo raddoppio dello spazio permette di memorizzare numeri astronomici.
Intervalli di Valore
Anche il BIGINT può essere Signed o Unsigned:
- Signed BIGINT: Da -9,223,372,036,854,775,808 a 9,223,372,036,854,775,807.
- Unsigned BIGINT: Da 0 a 18,446,744,073,709,551,615.
Quando usare BIGINT
Il BIGINT è indispensabile quando i dati superano i 4 miliardi di record. Casi d'uso reali includono:
- Sistemi di Log: Un server che registra ogni singola richiesta HTTP può generare miliardi di righe in pochi mesi.
- Applicazioni Globali: Piattaforme come Facebook o Twitter, dove il numero di post o di interazioni supera di gran lunga il limite dell'INT.
- Transazioni Finanziarie: Quando si lavora con micro-centisimi o valori monetari convertiti in interi per evitare errori di arrotondamento dei floating point.
- ID Generati Globalmente: Se utilizzi algoritmi come Snowflake ID per generare identificativi unici distribuiti.
Confronto Tecnico: Perché non usare sempre BIGINT?
Se il BIGINT può contenere tutto ciò che contiene un INT e molto di più, perché non impostare ogni colonna numerica come BIGINT? La risposta risiede nell'efficienza delle risorse.
1. Spazio su Disco
Sebbene 4 byte di differenza sembrino insignificanti, moltiplicali per milioni di righe. Se hai una tabella con 100 milioni di record e usi BIGINT invece di INT per tre diverse colonne, stai sprecando centinaia di megabyte di spazio su disco senza alcun beneficio reale.
2. Performance della Memoria RAM (Buffer Pool)
MySQL carica gli indici delle tabelle nella memoria RAM (specialmente con il motore InnoDB) per velocizzare le query. Gli indici basati su BIGINT occupano il doppio dello spazio rispetto a quelli basati su INT. Questo significa che meno record possono essere mantenuti in cache, costringendo il database a leggere più spesso dal disco, rallentando drasticamente le performance del sito web.
3. CPU e Allineamento
L'elaborazione di interi a 64 bit su architetture a 32 bit (ormai rare ma esistenti) è più lenta. Anche su sistemi moderni a 64 bit, l'ottimizzazione della memoria cache della CPU è più efficiente quando i dati sono compatti.
Esempi Pratici di Implementazione
Vediamo ora come implementare correttamente questi tipi di dato in uno scenario reale di programmazione web.
Scenario 1: Un Blog Personale
In un blog, il numero di articoli e commenti raramente supererà i 2 miliardi. In questo caso, l'INT è la scelta ottimale.
CREATE TABLE posts (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT,
views INT UNSIGNED DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Spiegazione: Usiamo INT UNSIGNED per l'ID e per le visualizzazioni perché non avremo mai ID negativi e 4 miliardi di visualizzazioni sono più che sufficienti per un blog.
Scenario 2: Un Sistema di Analisi Traffico (Big Data)
Immaginiamo di creare un sistema che traccia ogni click di ogni utente su un sito di e-commerce globale. Qui l'INT fallirebbe rapidamente.
CREATE TABLE user_clicks (
click_id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id INT UNSIGNED NOT NULL,
page_id INT UNSIGNED NOT NULL,
clicked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX (user_id)
);
Spiegazione: click_id è BIGINT perché il numero di click totali supererà rapidamente i 4 miliardi. Tuttavia, user_id e page_id rimangono INT perché è improbabile che il sito abbia più di 4 miliardi di utenti o pagine diverse.
Scenario 3: Migrazione da INT a BIGINT
Cosa succede se hai scelto INT e improvvisamente raggiungi il limite? Devi alterare la tabella. Attenzione: su tabelle enormi, questa operazione può bloccare il database per ore.
-- Operazione rischiosa su tabelle grandi
ALTER TABLE posts MODIFY COLUMN id BIGINT UNSIGNED AUTO_INCREMENT;
Spiegazione: Questo comando cambia il tipo di dato. In produzione, per tabelle con milioni di righe, si consigliano strumenti come pt-online-schema-change di Percona per evitare il downtime.
Errori Comuni e FAQ
L'errore del "Integer Overflow"
L'errore più comune è l'overflow. Quando una colonna INT SIGNED raggiunge 2,147,483,647 e si tenta di inserire un altro valore, MySQL potrebbe restituire un errore o, a seconda della configurazione, "troncare" il valore al massimo possibile. Questo causa bug catastrofici dove i nuovi record non vengono creati o ricevono ID duplicati.
Domanda: Posso usare BIGINT per i numeri di telefono?
Risposta: No. I numeri di telefono non sono numeri con cui si fanno calcoli matematici. Inoltre, spesso iniziano con lo zero (che verrebbe rimosso da un tipo numerico) o contengono il segno "+". Usa sempre VARCHAR per i numeri di telefono.
Domanda: E per i prezzi?
Risposta: Per i prezzi non usare né INT né BIGINT, ma DECIMAL(10,2). Se invece vuoi lavorare in "centesimi" per evitare i decimali (tecnica comune in Stripe e altri gateway di pagamento), allora INT o BIGINT sono ottime scelte.
Riepilogo Finale e Tabella Comparativa
| Caratteristica | INT | BIGINT |
|---|---|---|
| Dimensione | 4 Byte | 8 Byte |
| Range Signed | $\approx \pm 2$ miliardi | $\approx \pm 9$ quintillioni |
| Range Unsigned | $0$ a $\approx 4$ miliardi | $0$ a $\approx 18$ quintillioni |
| Performance | Molto Alta | Alta (ma più pesante in RAM) |
| Uso Consigliato | ID standard, conteggi medi | ID globali, Log, Big Data |
Prossimi Passi
Ora che conosci la differenza tra INT e BIGINT, puoi approfondire l'ottimizzazione del tuo database esplorando altri tipi di dato interi più piccoli:
- TINYINT: Occupa 1 byte (da -128 a 127). Ideale per booleani (0 o 1) o stati (es. 0: inattivo, 1: attivo, 2: sospeso).
- SMALLINT: Occupa 2 byte (da -32,768 a 32,767). Utile per piccoli elenchi o anni.
- MEDIUMINT: Occupa 3 byte. Una via di mezzo tra SMALLINT e INT.
Ti consiglio di studiare anche l'indicizzazione delle tabelle e come la scelta del tipo di dato influenzi la velocità di ricerca (B-Tree index), per trasformare il tuo database da semplice contenitore a macchina ad alte prestazioni.