W3docs

PHP MySQL Select com Limit: Guia Completo

Aprenda a usar a cláusula LIMIT do MySQL no PHP para limitar linhas, pular registros com OFFSET e criar paginação segura com prepared statements.

Em um banco de dados, muitas vezes você quer apenas uma parte de uma tabela — os dez posts mais recentes, a primeira página de resultados de busca, um único "melhor pontuador" — em vez de todas as linhas. A cláusula LIMIT em uma instrução SELECT do MySQL define quantas linhas a consulta pode retornar. Combinada com um OFFSET, ela é a base da paginação: servir grandes conjuntos de resultados uma página por vez, em vez de carregar milhares de linhas na memória.

Este capítulo aborda a sintaxe de LIMIT, o OFFSET que pula linhas, como construir uma paginação segura com prepared statements e as armadilhas que costumam pegar as pessoas de surpresa. Ele pressupõe que você já saiba conectar-se ao MySQL e executar um SELECT básico.

Sintaxe de SELECT com LIMIT

A forma básica define um número máximo de linhas a retornar:

SELECT column1, column2, ... FROM table_name LIMIT row_count;

Para também pular linhas do início do conjunto de resultados, adicione um deslocamento (offset). O MySQL aceita duas grafias equivalentes:

SELECT ... FROM table_name LIMIT offset, row_count;   -- offset first
SELECT ... FROM table_name LIMIT row_count OFFSET offset;  -- explicit OFFSET

O que cada parte significa:

  • row_count — o número máximo de linhas a retornar.
  • offset — quantas linhas pular antes de começar a retornar resultados. O deslocamento é baseado em zero, portanto OFFSET 0 começa na primeira linha.
  • LIMIT 10, 5 retorna 5 linhas a partir da posição seguinte às 10 primeiras (ou seja, as linhas 11 a 15). A mesma consulta fica mais natural escrita como LIMIT 5 OFFSET 10.

LIMIT sem ORDER BY é não determinístico. Sem um ORDER BY explícito, o MySQL pode retornar as linhas em qualquer ordem, de modo que "as 2 primeiras linhas" podem variar de uma execução para outra. Sempre combine LIMIT com ORDER BY quando a ordem das linhas importar.

Exemplo: recuperando as primeiras linhas

Considere uma tabela chamada students:

+----+---------+--------+-------+
| id | name    | class  | marks |
+----+---------+--------+-------+
|  1 | John    | 10     | 90    |
|  2 | Michael | 9      | 85    |
|  3 | Jessica | 8      | 80    |
|  4 | Sarah   | 10     | 88    |
|  5 | David   | 9      | 72    |
+----+---------+--------+-------+

Para buscar os dois primeiros alunos (ordenados por id para que o resultado seja estável):

<?php
$conn = mysqli_connect("localhost", "username", "password", "database");

$query = "SELECT id, name, class, marks FROM students ORDER BY id LIMIT 2";
$result = mysqli_query($conn, $query);

while ($row = mysqli_fetch_assoc($result)) {
    echo "ID: {$row['id']} Name: {$row['name']} Class: {$row['class']} Marks: {$row['marks']}<br>";
}

mysqli_close($conn);
?>

Saída:

ID: 1 Name: John Class: 10 Marks: 90
ID: 2 Name: Michael Class: 9 Marks: 85

Observe o uso de mysqli_fetch_assoc() (apenas array associativo) em vez de mysqli_fetch_array(), que retorna chaves numéricas e de texto ao mesmo tempo e, por isso, aloca o dobro de memória para os mesmos dados.

Pulando linhas com OFFSET

Para obter a segunda página de dois alunos — as linhas 3 e 4 — pule as duas primeiras:

<?php
$conn = mysqli_connect("localhost", "username", "password", "database");

$query = "SELECT id, name, marks FROM students ORDER BY id LIMIT 2 OFFSET 2";
$result = mysqli_query($conn, $query);

while ($row = mysqli_fetch_assoc($result)) {
    echo "ID: {$row['id']} Name: {$row['name']} Marks: {$row['marks']}<br>";
}

mysqli_close($conn);
?>

Saída:

ID: 3 Name: Jessica Marks: 80
ID: 4 Name: Sarah Marks: 88

Construindo uma paginação segura

Na paginação real, o número da página vem da entrada do usuário (uma URL como ?page=3), então o offset nunca deve ser concatenado diretamente no SQL. Use um prepared statement com parâmetros inteiros vinculados:

<?php
$conn = mysqli_connect("localhost", "username", "password", "database");

$perPage = 2;
$page    = max(1, (int) ($_GET['page'] ?? 1)); // force a positive integer
$offset  = ($page - 1) * $perPage;

$stmt = mysqli_prepare(
    $conn,
    "SELECT id, name, marks FROM students ORDER BY id LIMIT ? OFFSET ?"
);
mysqli_stmt_bind_param($stmt, "ii", $perPage, $offset); // "ii" = two integers
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);

while ($row = mysqli_fetch_assoc($result)) {
    echo "ID: {$row['id']} Name: {$row['name']} Marks: {$row['marks']}<br>";
}

mysqli_close($conn);
?>

Converter a página com (int) e vinculá-la como inteiro ("ii") previne SQL injection, já que LIMIT/OFFSET aceitam apenas números de qualquer maneira.

Para exibir "Página 3 de N", você também precisa do número total de linhas. Execute uma consulta COUNT(*) separada e divida pelo tamanho da página:

$total = (int) mysqli_fetch_row(
    mysqli_query($conn, "SELECT COUNT(*) FROM students")
)[0];
$pageCount = (int) ceil($total / $perPage); // 5 rows / 2 per page = 3 pages

Armadilhas comuns

  • Sem ORDER BY, sem garantia. Como mencionado acima, LIMIT só retorna uma fatia estável quando combinado com um ORDER BY em uma coluna única (ou com critério de desempate).
  • Offsets grandes são lentos. LIMIT 20 OFFSET 100000 ainda obriga o MySQL a percorrer e descartar 100.000 linhas. Para paginação profunda, prefira a paginação keyset — WHERE id > :lastSeenId ORDER BY id LIMIT 20 — que vai direto ao ponto certo usando o índice. Veja WHERE.
  • OFFSET não pode ser usado sozinho. O MySQL exige um LIMIT sempre que você usa OFFSET. Para pular linhas e retornar "todo o resto", use um limite enorme: LIMIT 18446744073709551615 OFFSET 10.
  • As páginas são indexadas a partir de zero internamente. Um erro clássico de off-by-one é esquecer que a página 1 corresponde a OFFSET 0, daí o ($page - 1) * $perPage acima.

Prática

Prática
Qual é a finalidade da palavra-chave 'LIMIT' no MySQL, conforme discutido no link fornecido?
Qual é a finalidade da palavra-chave 'LIMIT' no MySQL, conforme discutido no link fornecido?
Was this page helpful?