Bài toán
Lấy N bản ghi bắt đầu từ vị trí thứ M (offset), có sắp xếp.
Giải pháp: Subquery với LIMIT + ORDER BY
Tạo bảng:
CREATE TABLE DemoTable618 (
StudentId INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
StudentFirstName VARCHAR(100)
);
INSERT INTO DemoTable618(StudentFirstName) VALUES
('David'), ('Chris'), ('Robert'), ('Sam'), ('Mike'), ('Carol'), ('Bob'), ('John');
Lấy 4 bản ghi từ StudentId >= 5, sắp xếp giảm dần:
SELECT * FROM (
SELECT StudentId, StudentFirstName
FROM DemoTable618
WHERE StudentId >= 5
ORDER BY StudentId
LIMIT 4
) AS tbl
ORDER BY tbl.StudentId DESC;
Kết quả:
+-----------+------------------+
| StudentId | StudentFirstName |
+-----------+------------------+
| 8 | John |
| 7 | Bob |
| 6 | Carol |
| 5 | Mike |
+-----------+------------------+
Giải thích
- Inner query: Lọc
StudentId >= 5, sắp xếpASC, lấyLIMIT 4(dòng 5,6,7,8). - Outer query: Sắp xếp lại
DESCđể hiển thị ngược (8,7,6,5).
Cách thay thế: OFFSET + LIMIT (Phân trang chuẩn)
-- Lấy trang 2, mỗi trang 4 dòng (bỏ qua 4 dòng đầu)
SELECT * FROM DemoTable618
ORDER BY StudentId
LIMIT 4 OFFSET 4;
Kết quả (ASC): 5,6,7,8. Muốn DESC: ORDER BY StudentId DESC LIMIT 4 OFFSET 4 → 4,3,2,1 (khác với ví dụ trên).
So sánh
| Phương pháp | Dùng khi |
|---|---|
| Subquery + 2 lần ORDER BY | Cần logic phức tạp: lọc → sort A → limit → sort B |
| OFFSET + LIMIT | Phân trang chuẩn, sort đơn giản |
| Keyset pagination (WHERE id > last_id) | Bảng lớn, hiệu năng cao, không dùng OFFSET |
Lưu ý hiệu năng
OFFSETlớn → chậm (MySQL vẫn phải đọc và bỏ qua các dòng offset).- Subquery tạo temporary table → tốn memory/disk.
- Luôn có index trên cột ORDER BY và WHERE.