MySQL Limit
Scopri come usare la clausola LIMIT di MySQL in Python per limitare i risultati, implementare la paginazione e gestire dataset di grandi dimensioni.
La clausola LIMIT controlla quante righe restituisce una query SELECT. Quando si lavora con tabelle di grandi dimensioni — migliaia o milioni di righe — recuperare tutti i record in una volta spreca memoria e rallenta l'applicazione. LIMIT consente di recuperare solo i record effettivamente necessari.
Questo capitolo mostra come usare LIMIT in Python con il pacchetto mysql-connector-python, inclusa la paginazione con OFFSET, la combinazione di LIMIT con ORDER BY e le buone pratiche per la gestione degli errori.
Prerequisiti
Assicurati che il connettore MySQL sia installato prima di eseguire gli esempi:
pip install mysql-connector-pythonTutti gli esempi presuppongono l'esistenza di una tabella customers in un database chiamato mydatabase. Puoi crearne una seguendo il capitolo Python MySQL Create Table.
Come funziona la clausola LIMIT
La sintassi di base limita il set di risultati a un numero fisso di righe:
SELECT * FROM table_name LIMIT n;Per saltare un certo numero di righe prima di iniziare il set di risultati, aggiungi OFFSET:
SELECT * FROM table_name LIMIT n OFFSET m;OFFSET m significa "salta le prime m righe". Questa è la base della navigazione pagina per pagina attraverso dataset di grandi dimensioni.
Recuperare un numero fisso di righe
L'esempio seguente si connette a un database MySQL e recupera solo i primi cinque clienti:
Recupera le prime 5 righe con LIMIT
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
mycursor.execute("SELECT * FROM customers LIMIT 5")
results = mycursor.fetchall()
for row in results:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mycursor:
mycursor.close()
if mydb.is_connected():
mydb.close()Il metodo fetchall() restituisce una lista di tuple — una tupla per ogni riga. Poiché la query limita già i risultati a cinque righe, la lista conterrà al massimo cinque elementi indipendentemente dal numero totale di righe nella tabella.
Usare LIMIT con OFFSET per la paginazione
OFFSET sposta la riga iniziale del risultato. Combinato con LIMIT, permette di implementare la paginazione: la pagina 1 mostra le righe 1–10, la pagina 2 mostra le righe 11–20, e così via.
La formula è: OFFSET = (page_number - 1) * page_size.
Recupera la pagina 2 dei risultati (righe 11–20)
import mysql.connector
from mysql.connector import Error
page_number = 2
page_size = 10
offset = (page_number - 1) * page_size # evaluates to 10
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
sql = "SELECT * FROM customers LIMIT %s OFFSET %s"
mycursor.execute(sql, (page_size, offset))
results = mycursor.fetchall()
for row in results:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mycursor:
mycursor.close()
if mydb.is_connected():
mydb.close()I segnaposto %s vengono sostituiti dal driver del connettore, che gestisce i valori in modo sicuro e previene le SQL injection. Non costruire mai i valori di LIMIT o OFFSET concatenando stringhe direttamente nella query.
Combinare LIMIT con ORDER BY
Senza ORDER BY, il database può restituire le righe in qualsiasi ordine. Quando si usa LIMIT si vuole quasi sempre un ordine prevedibile — altrimenti la pagina 1 e la pagina 2 potrebbero contenere righe sovrapposte o arbitrarie.
Recupera i 5 clienti aggiunti più di recente
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Sort by id descending so the newest rows come first, then take 5
mycursor.execute("SELECT * FROM customers ORDER BY id DESC LIMIT 5")
results = mycursor.fetchall()
for row in results:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mycursor:
mycursor.close()
if mydb.is_connected():
mydb.close()In MySQL l'ordine di valutazione è FROM → WHERE → ORDER BY → LIMIT, quindi LIMIT opera sempre sul set di risultati ordinato.
Recuperare una singola riga con fetchone()
Quando si sa di aver bisogno di una sola riga — ad esempio per cercare un record tramite chiave primaria — puoi limitare la query a una riga e usare fetchone() invece di fetchall(). Questo evita di allocare una lista per un risultato che non verrà mai usato:
Recupera una singola riga
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
mycursor.execute("SELECT * FROM customers LIMIT 1")
row = mycursor.fetchone()
if row:
print(row)
else:
print("No records found.")
except Error as e:
print(f"Error: {e}")
finally:
if mycursor:
mycursor.close()
if mydb.is_connected():
mydb.close()fetchone() restituisce una singola tupla oppure None se il set di risultati è vuoto.
Creare una funzione di paginazione riutilizzabile
Per le applicazioni reali è conveniente racchiudere la logica di paginazione in una funzione, così il codice chiamante rimane pulito:
Helper paginate() riutilizzabile
import mysql.connector
from mysql.connector import Error
def paginate(cursor, table, page, page_size=10):
"""Return one page of rows from *table*.
Args:
cursor: An active mysql.connector cursor.
table: Name of the table to query (string).
page: 1-based page number.
page_size: Number of rows per page (default 10).
Returns:
A list of row tuples, or an empty list when no rows remain.
"""
offset = (page - 1) * page_size
# Table names cannot be parameterised, so validate the name first.
if not table.isidentifier():
raise ValueError(f"Invalid table name: {table!r}")
sql = f"SELECT * FROM `{table}` LIMIT %s OFFSET %s"
cursor.execute(sql, (page_size, offset))
return cursor.fetchall()
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Print the first three pages
for page in range(1, 4):
rows = paginate(mycursor, "customers", page=page, page_size=5)
if not rows:
print(f"Page {page}: no more rows.")
break
print(f"--- Page {page} ---")
for row in rows:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mycursor:
mycursor.close()
if mydb.is_connected():
mydb.close()Nota che i nomi delle tabelle non possono essere passati come parametri %s — il connettore non supporta la parametrizzazione degli identificatori. Il controllo isidentifier() protegge da injection tramite l'argomento del nome della tabella.
Errori comuni
LIMIT senza ORDER BY produce risultati imprevedibili. MySQL non garantisce un ordine stabile delle righe a meno che non si specifichi ORDER BY. Due query identiche potrebbero restituire righe diverse se la tabella viene modificata tra una chiamata e l'altra.
Valori di OFFSET elevati sono lenti. LIMIT 10 OFFSET 1000000 obbliga comunque MySQL a scansionare e scartare un milione di righe prima di restituirne dieci. Per la paginazione profonda su tabelle molto grandi, considera la keyset pagination (detta anche cursor-based pagination): registra l'ultimo id visto nella pagina precedente e usa WHERE id > last_id LIMIT 10.
Non costruire i valori di LIMIT tramite concatenazione di stringhe. Usa i segnaposto %s oppure, se il valore è calcolato in Python, assicurati che sia un intero semplice prima di incorporarlo nella stringa SQL.
Riepilogo
| Obiettivo | Schema SQL |
|---|---|
| Prime N righe | SELECT ... LIMIT N |
| Salta M righe, prendi N | SELECT ... LIMIT N OFFSET M |
| Pagina P di dimensione N | LIMIT N OFFSET (P-1)*N |
| Solo una riga | SELECT ... LIMIT 1 + fetchone() |
| Prime N ordinate | SELECT ... ORDER BY col LIMIT N |
Capitoli correlati
- Python MySQL Select — interrogare le righe di una tabella
- Python MySQL Where — filtrare i risultati con condizioni
- Python MySQL Order By — ordinare i set di risultati
- Python MySQL Join — combinare più tabelle