W3docs

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-python

Tutti 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 è FROMWHEREORDER BYLIMIT, 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.

ObiettivoSchema SQL
Prime N righeSELECT ... LIMIT N
Salta M righe, prendi NSELECT ... LIMIT N OFFSET M
Pagina P di dimensione NLIMIT N OFFSET (P-1)*N
Solo una rigaSELECT ... LIMIT 1 + fetchone()
Prime N ordinateSELECT ... ORDER BY col LIMIT N

Capitoli correlati

Was this page helpful?