MySQL Limit
Узнайте, как использовать MySQL LIMIT в Python для ограничения результатов, реализации пагинации и работы с большими наборами данных.
Оператор LIMIT управляет количеством строк, которые возвращает запрос SELECT. При работе с большими таблицами — тысячами или миллионами строк — загрузка всех записей сразу расходует память и замедляет приложение. LIMIT позволяет получать только те записи, которые действительно нужны.
В этой главе показано, как использовать LIMIT в Python с пакетом mysql-connector-python, включая пагинацию с OFFSET, совместное использование LIMIT с ORDER BY и рекомендации по обработке ошибок.
Предварительные требования
Перед запуском примеров убедитесь, что MySQL connector установлен:
pip install mysql-connector-pythonВо всех примерах предполагается, что в базе данных mydatabase существует таблица customers. Создать её можно, следуя главе Python MySQL Create Table.
Как работает оператор LIMIT
Базовый синтаксис ограничивает результирующий набор фиксированным количеством строк:
SELECT * FROM table_name LIMIT n;Чтобы пропустить несколько строк перед началом результирующего набора, добавьте OFFSET:
SELECT * FROM table_name LIMIT n OFFSET m;OFFSET m означает «пропустить первые m строк». Это основа постраничной навигации по большим наборам данных.
Получение фиксированного количества строк
Пример ниже подключается к базе данных MySQL и извлекает только первых пять клиентов:
Получение первых 5 строк с помощью 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()Метод fetchall() возвращает список кортежей — по одному кортежу на каждую строку. Поскольку запрос уже ограничивает результаты пятью строками, список будет содержать не более пяти элементов независимо от общего числа строк в таблице.
Использование LIMIT с OFFSET для пагинации
OFFSET смещает начальную строку результата. В сочетании с LIMIT это позволяет реализовать пагинацию: страница 1 показывает строки 1–10, страница 2 — строки 11–20 и так далее.
Формула: OFFSET = (page_number - 1) * page_size.
Получение 2-й страницы результатов (строки 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()Заполнители %s подставляются драйвером connector, который безопасно обрабатывает значения и предотвращает SQL-инъекции. Никогда не формируйте значения LIMIT или OFFSET путём конкатенации строк непосредственно в запросе.
Совместное использование LIMIT с ORDER BY
Без ORDER BY база данных может возвращать строки в произвольном порядке. При использовании LIMIT почти всегда нужен предсказуемый порядок — иначе страница 1 и страница 2 могут содержать перекрывающиеся или случайные строки.
Получение 5 последних добавленных клиентов
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()В MySQL порядок выполнения: FROM → WHERE → ORDER BY → LIMIT, поэтому LIMIT всегда применяется к отсортированному результирующему набору.
Получение одной строки с fetchone()
Когда заранее известно, что нужна только одна строка — например, при поиске записи по первичному ключу — можно ограничить запрос одной строкой и использовать fetchone() вместо fetchall(). Это позволяет избежать выделения памяти под список, который не будет использован:
Получение одной строки
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() возвращает один кортеж или None, если результирующий набор пуст.
Создание многократно используемой функции пагинации
В реальных приложениях удобно обернуть логику пагинации в функцию, чтобы вызывающий код оставался чистым:
Вспомогательная функция paginate()
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()Обратите внимание, что имена таблиц нельзя передавать как параметры %s — connector не поддерживает параметризацию идентификаторов. Проверка isidentifier() защищает от инъекций через аргумент с именем таблицы.
Распространённые ошибки
LIMIT без ORDER BY даёт непредсказуемые результаты. MySQL не гарантирует стабильный порядок строк, если не указан ORDER BY. Два одинаковых запроса могут вернуть разные строки, если таблица была изменена между вызовами.
Большие значения OFFSET работают медленно. LIMIT 10 OFFSET 1000000 всё равно заставляет MySQL просканировать и отбросить миллион строк, прежде чем вернуть десять. Для глубокой пагинации в очень больших таблицах рассмотрите keyset-пагинацию (также называемую cursor-based pagination): сохраняйте последний просмотренный id и используйте WHERE id > last_id LIMIT 10.
Не формируйте значения LIMIT путём конкатенации строк. Используйте заполнители %s или, если значение вычисляется в Python, убедитесь, что оно является целым числом, прежде чем встраивать его в строку SQL.
Итоги
| Цель | Шаблон SQL |
|---|---|
| Первые N строк | SELECT ... LIMIT N |
| Пропустить M строк, взять N | SELECT ... LIMIT N OFFSET M |
| Страница P размером N | LIMIT N OFFSET (P-1)*N |
| Только одна строка | SELECT ... LIMIT 1 + fetchone() |
| Первые N в нужном порядке | SELECT ... ORDER BY col LIMIT N |
Связанные главы
- Python MySQL Select — получение строк из таблицы
- Python MySQL Where — фильтрация результатов с условиями
- Python MySQL Order By — сортировка результирующих наборов
- Python MySQL Join — объединение нескольких таблиц