Tre errori sui database che vedo in ogni progetto PHP
Laravel & PHP

Tre errori sui database che vedo in ogni progetto PHP

AG
Alex Gentili
13 March 2026 5 min 301 letture

Dopo vent'anni di Laravel e PHP, continuo a vedere gli stessi errori sui database. Ti racconto i tre più comuni e come li risolvo nei miei progetti a Trento.

Settimana scorsa ho preso in carico un gestionale che un cliente aveva fatto sviluppare altrove. Il software funzionava, per carità, ma andava lento. Molto lento. Ho aperto il codice e ho trovato tutti e tre gli errori di cui voglio parlarti oggi.

Non sto parlando di errori da principiante. Sto parlando di scelte che fanno anche sviluppatori con esperienza, magari perché vanno di fretta o perché "tanto funziona". Il problema è che funziona fino a quando il database non cresce. Poi arrivano le chiamate disperate.

Primo errore: query dentro i loop (il classico N+1)

Questo è il killer numero uno delle performance. Lo vedo ovunque, anche in progetti che sembrano ben fatti. Il concetto è semplice: hai un loop che per ogni elemento fa una query al database. Sembra innocuo, ma è micidiale.

Un mio cliente aveva un gestionale personalizzato per gestire le prenotazioni del suo ristorante. La pagina con l'elenco delle prenotazioni del mese impiegava 8 secondi a caricare. Otto secondi. Ho guardato il codice e c'era un bel loop che per ogni prenotazione faceva una query per recuperare i dati del cliente.

200 prenotazioni = 201 query (una per l'elenco, 200 per i dettagli). Un massacro.

La soluzione in Laravel è banale: eager loading. Invece di caricare le relazioni al volo, le carichi tutte insieme:

// Male - N+1 queries
$prenotazioni = Prenotazione::all();
foreach($prenotazioni as $p) {
    echo $p->cliente->nome; // Query per ogni cliente
}

// Bene - 2 queries totali
$prenotazioni = Prenotazione::with('cliente')->get();
foreach($prenotazioni as $p) {
    echo $p->cliente->nome; // Nessuna query, già caricato
}

Otto secondi sono diventati 0.3 secondi. Il cliente pensava di dover cambiare server. Gli è bastato cambiare una riga di codice.

Secondo errore: selezionare sempre tutti i campi

Questo è più subdolo perché non lo noti subito. Quante volte hai scritto SELECT * o usato Model::all() senza pensarci? Io lo facevo sempre, fino a quando non mi sono trovato con tabelle che avevano campi TEXT o JSON giganti.

Lavoravo a una web app su misura per un'associazione culturale che gestiva eventi. La tabella degli eventi aveva un campo 'descrizione_completa' con testi lunghissimi e un campo 'immagini' con array JSON di path alle foto. Ogni volta che facevo Event::all() mi portavo dietro megabyte di dati che non mi servivano.

La lista eventi nella dashboard admin doveva mostrare solo titolo, data e stato. Ma caricavo tutto. Risultato: pagina lenta, memoria sprecata, server sotto stress.

// Male - carichi tutto anche se non serve
$eventi = Event::all();

// Bene - carichi solo quello che ti serve
$eventi = Event::select('id', 'titolo', 'data', 'stato')->get();

// Ancora meglio con Eloquent
$eventi = Event::query()
    ->select(['id', 'titolo', 'data', 'stato'])
    ->where('data', '>=', now())
    ->orderBy('data')
    ->get();

Ora specifico sempre i campi. Sempre. Costa zero fatica in più e fa una differenza enorme quando il database cresce. E i database crescono sempre, credimi.

Terzo errore: non usare gli indici (o usarli male)

Gli indici sono quella cosa che tutti sanno di dover usare ma che nessuno usa davvero finché il database non rallenta. Poi si corre ai ripari, ma intanto hai perso tempo e clienti.

Un caso recente: un e-commerce a Trento con 15.000 prodotti. La ricerca per categoria era lentissima. Ho controllato: nessun indice sulla colonna 'categoria_id'. Ogni ricerca scansionava tutte le righe. Una follia.

In Laravel le migration ti rendono la vita facile:

Schema::create('prodotti', function (Blueprint $table) {
    $table->id();
    $table->string('nome');
    $table->unsignedBigInteger('categoria_id');
    $table->decimal('prezzo', 8, 2);
    $table->boolean('attivo')->default(true);
    $table->timestamps();
    
    // Indici essenziali
    $table->index('categoria_id');
    $table->index('attivo');
    $table->index(['categoria_id', 'attivo']); // Indice composito
});

Attenzione però: più indici non significa più veloce. Ogni indice rallenta gli insert e update. Io seguo questa regola: metto indici solo sulle colonne che uso nei WHERE, negli ORDER BY e nei JOIN. E uso EXPLAIN per verificare che MySQL li usi davvero.

Puoi controllare se i tuoi indici vengono usati direttamente da Laravel:

DB::enableQueryLog();
$prodotti = Prodotto::where('categoria_id', 5)->get();
dd(DB::getQueryLog());

Poi prendi la query e la provi con EXPLAIN su MySQL. Se vedi "Using index" sei a posto. Se vedi "Using filesort" o "Using temporary", hai un problema.

La regola che uso sempre

Quando sviluppo un gestionale o una web app, ho una regola ferrea: testo sempre con dati realistici. Non 10 righe di esempio, ma migliaia. Creo seeder in Laravel che mi riempiono il database con dati fake ma verosimili.

Questo mi fa vedere subito se ho fatto uno di questi tre errori. Perché con 10 righe non noti niente. Con 10.000 righe, ogni errore salta fuori.

Un trucco che uso: creo un comando Artisan che mi genera traffico simulato sul database. Lo lancio, apro Laravel Telescope o Debugbar, e guardo quante query fa ogni pagina. Se vedo numeri strani (tipo 200 query per una pagina), so che c'è un N+1 nascosto da qualche parte.

Nel mio lavoro qui a Trento, spesso mi chiamano per ottimizzare progetti esistenti. Nove volte su dieci il problema è uno di questi tre. Forse sono noioso a ripeterlo, ma questi errori costano soldi veri: server più potenti, utenti frustrati, bounce rate alle stelle.

La cosa bella è che sono tutti risolvibili. Non servono mesi di refactoring, basta sapere dove guardare. Se hai un progetto Laravel o PHP che va lento, scrivimi. Magari è solo questione di aggiungere qualche indice e un paio di with(). O magari c'è qualcosa di più grosso, ma almeno lo scopriamo insieme davanti a un caffè.

#Laravel #PHP #Database #Performance #MySQL

Ti è piaciuto l'articolo?

Condividilo con chi potrebbe trovarlo utile

Ti serve aiuto con questo argomento?

Sono disponibile per consulenze, sviluppo e supporto tecnico. Contattami per discutere il tuo progetto.

Accessibilità

Dimensione Testo

Utilizzo dei Cookie

Questo sito utilizza cookie tecnici necessari per il funzionamento e, con il tuo consenso, cookie analytics per migliorare l'esperienza utente. Privacy Policy • Cookie Policy