W3docs

PHP MySQL SELECT mit LIMIT: Ein umfassender Leitfaden

Erfahren Sie, wie Sie mit der LIMIT-Klausel in PHP MySQL nur eine bestimmte Anzahl von Datensätzen abrufen und Paginierung sicher umsetzen.

In einer Datenbank möchte man oft nur einen Ausschnitt einer Tabelle — die neuesten zehn Beiträge, die erste Seite der Suchergebnisse, einen einzigen „Spitzenreiter" — und nicht alle Zeilen. Die LIMIT-Klausel in einer MySQL-SELECT-Anweisung begrenzt die Anzahl der zurückgegebenen Zeilen. Kombiniert mit einem OFFSET bildet sie die Grundlage der Paginierung: große Ergebnismengen werden Seite für Seite ausgegeben, anstatt Tausende von Zeilen in den Arbeitsspeicher zu laden.

Dieses Kapitel behandelt die LIMIT-Syntax, das zeilenüberspringende OFFSET, den sicheren Aufbau von Paginierung mit Prepared Statements sowie häufige Fallstricke. Es wird vorausgesetzt, dass Sie bereits eine MySQL-Verbindung herstellen und ein einfaches SELECT ausführen können.

Syntax von SELECT mit LIMIT

Die grundlegende Form legt eine maximale Anzahl zurückzugebender Zeilen fest:

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

Um auch Zeilen am Anfang der Ergebnismenge zu überspringen, fügen Sie einen Offset hinzu. MySQL unterstützt zwei gleichwertige Schreibweisen:

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

Bedeutung der einzelnen Teile:

  • row_count — die maximale Anzahl der zurückzugebenden Zeilen.
  • offset — wie viele Zeilen vor dem Start der Rückgabe übersprungen werden. Der Offset ist nullbasiert, d. h. OFFSET 0 beginnt bei der ersten Zeile.
  • LIMIT 10, 5 gibt 5 Zeilen zurück, beginnend nach den ersten 10 (also Zeilen 11–15). Dieselbe Abfrage lässt sich besser lesbar als LIMIT 5 OFFSET 10 schreiben.

LIMIT ohne ORDER BY ist nicht deterministisch. Ohne ein explizites ORDER BY kann MySQL die Zeilen in beliebiger Reihenfolge zurückgeben, sodass „die ersten 2 Zeilen" von Ausführung zu Ausführung variieren können. Kombinieren Sie LIMIT immer mit ORDER BY, wenn die Zeilenreihenfolge von Bedeutung ist.

Beispiel: Abrufen der ersten Zeilen

Betrachten Sie eine Tabelle namens 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    |
+----+---------+--------+-------+

Um die ersten zwei Studierenden abzurufen (nach id sortiert, damit das Ergebnis stabil ist):

<?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);
?>

Ausgabe:

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

Beachten Sie die Verwendung von mysqli_fetch_assoc() (nur assoziatives Array) anstelle von mysqli_fetch_array(), das sowohl numerische als auch string-basierte Schlüssel zurückgibt und damit doppelt so viel Speicher für dieselben Daten belegt.

Zeilen mit OFFSET überspringen

Um die zweite Seite mit zwei Studierenden abzurufen — Zeilen 3 und 4 — überspringen Sie die ersten beiden:

<?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);
?>

Ausgabe:

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

Paginierung sicher aufbauen

Bei echter Paginierung kommt die Seitennummer aus der Benutzereingabe (einer URL wie ?page=3), daher darf der Offset niemals direkt in SQL eingebettet werden. Verwenden Sie ein Prepared Statement mit gebundenen Integer-Parametern:

<?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);
?>

Das Umwandeln der Seitenzahl in (int) und das Binden als Integer ("ii") verhindert SQL-Injection, da LIMIT/OFFSET ohnehin nur Zahlen akzeptieren.

Um „Seite 3 von N" anzuzeigen, benötigen Sie auch die Gesamtzahl der Zeilen. Führen Sie eine separate COUNT(*)-Abfrage aus und teilen Sie durch die Seitengröße:

$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

Häufige Fallstricke

  • Kein ORDER BY, keine Garantie. Wie oben erwähnt, gibt LIMIT nur dann einen stabilen Ausschnitt zurück, wenn es mit einem ORDER BY auf einer eindeutigen (oder tie-breaking) Spalte kombiniert wird.
  • Große Offsets sind langsam. LIMIT 20 OFFSET 100000 lässt MySQL trotzdem 100.000 Zeilen durchsuchen und verwerfen. Für tiefe Paginierung ist Keyset-Paginierung vorzuziehen — WHERE id > :lastSeenId ORDER BY id LIMIT 20 — die dank des Index direkt zur richtigen Stelle springt. Siehe WHERE.
  • OFFSET kann nicht alleine verwendet werden. MySQL erfordert ein LIMIT, wenn OFFSET eingesetzt wird. Um Zeilen zu überspringen und „alle übrigen" zurückzugeben, verwenden Sie ein sehr großes Limit: LIMIT 18446744073709551615 OFFSET 10.
  • Seiten sind intern nullindiziert. Ein häufiger Off-by-one-Fehler ist das Vergessen, dass Seite 1 auf OFFSET 0 abgebildet wird, daher ($page - 1) * $perPage im obigen Beispiel.

Übungen

Übung
Was ist der Zweck des Schlüsselworts 'LIMIT' in MySQL?
Was ist der Zweck des Schlüsselworts 'LIMIT' in MySQL?
Was this page helpful?