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 OFFSETBedeutung 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 0beginnt bei der ersten Zeile.LIMIT 10, 5gibt 5 Zeilen zurück, beginnend nach den ersten 10 (also Zeilen 11–15). Dieselbe Abfrage lässt sich besser lesbar alsLIMIT 5 OFFSET 10schreiben.
LIMITohneORDER BYist nicht deterministisch. Ohne ein explizitesORDER BYkann MySQL die Zeilen in beliebiger Reihenfolge zurückgeben, sodass „die ersten 2 Zeilen" von Ausführung zu Ausführung variieren können. Kombinieren SieLIMITimmer mitORDER 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: 85Beachten 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: 88Paginierung 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 pagesHäufige Fallstricke
- Kein
ORDER BY, keine Garantie. Wie oben erwähnt, gibtLIMITnur dann einen stabilen Ausschnitt zurück, wenn es mit einemORDER BYauf einer eindeutigen (oder tie-breaking) Spalte kombiniert wird. - Große Offsets sind langsam.
LIMIT 20 OFFSET 100000lä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. SieheWHERE. OFFSETkann nicht alleine verwendet werden. MySQL erfordert einLIMIT, wennOFFSETeingesetzt 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 0abgebildet wird, daher($page - 1) * $perPageim obigen Beispiel.