La pagination (output di pagine) consente di elaborare grandi risultati SELECT senza un eccessivo carico sul server e sull'applicazione. I principali approcci:
Esempio (LIMIT/OFFSET)
SELECT * FROM Orders ORDER BY OrderID LIMIT 100 OFFSET 1000;
Questa query restituisce le righe 1011–1110. Ma l'OFFSET costringe il server a riesaminare e saltare le prime 1000 righe — quindi diventa lento con una paginazione profonda.
Esempio (Keyset/Seek method)
SELECT * FROM Orders WHERE OrderID > 1110 ORDER BY OrderID LIMIT 100;
Questa query cerca rapidamente la pagina successiva, senza sprecare risorse per contare l'OFFSET, particolarmente efficace in presenza di un indice su OrderID.
Trabocchetto: "Perché la pagination tramite LIMIT/OFFSET può funzionare male con grandi volumi di dati e come migliorarlo?"
Risposta: La difficoltà sta nel fatto che l'OFFSET richiede al server di scannerizzare e ordinare tutte le righe precedenti — quindi più ci si allontana nelle pagine, più diventa lenta. L'ottimizzazione — passare a keyset/seek paging: scegliere non per offset, ma per la chiave dell'ultima riga della pagina precedente.
-- Otteniamo la pagina successiva tramite chiave SELECT * FROM Orders WHERE OrderID > @LastOrderID ORDER BY OrderID LIMIT 100;
Storia
Progetto: Marketplace, database degli ordini per 5 anni (50 milioni di righe)
Errore: È stato utilizzato OFFSET per la pagination degli ordini dei clienti più vecchi. Le query con OFFSET > 1 milione iniziavano a impiegare 30–60 secondi. Ciò ha influito su report e API — questo ha caricato CPU del server e aumentato il tempo di attesa in coda.
Storia
Progetto: CRM aziendale, report sui clienti.
Errore: Nella pagination non è stato considerato l'ordine di ordinamento e non sono stati utilizzati indici. La performance e il controllo dell'integrità delle selezioni sono diminuiti — gli utenti ricevevano le stesse righe su pagine diverse a causa delle modifiche nella tabella.
Storia
Progetto: Piattaforma finanziaria, dashboard.
Errore: Le complessità di pagination erano costruite tramite SQL dinamico generato senza bind-variabili, il che ha portato a SQL injection e problemi di supporto della transazionalità tra le pagine di dati.