ORDER BY與LIMIT是構建分頁、排行榜、最新列表等功能的核心組合。本文詳細講解語法、參數陷阱、性能優化及實戰技巧。
SELECT column_list
FROM table_name
[WHERE condition]
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...;
ASC:升序(默認),DESC:降序-- 按ID降序(最新優先)
SELECT uid, username FROM user ORDER BY uid DESC;
-- 按注冊時間降序,取最新10名用戶
SELECT username FROM user ORDER BY regdate DESC LIMIT 10;
-- 多列排序:按部門升序,部門內按薪資降序
SELECT dept, name, salary FROM employee ORDER BY dept ASC, salary DESC;
-- 形式一:指定偏移量和行數
LIMIT offset, row_count
-- 形式二:僅指定行數(偏移量默認0)
LIMIT row_count
offset:起始行偏移量(從0開始)row_count:返回最大行數| 頁碼(1-based) | 每頁條數 | offset | LIMIT子句 |
|---|---|---|---|
| 1 | 10 | 0 | LIMIT 0, 10 或 LIMIT 10 |
| 2 | 10 | 10 | LIMIT 10, 10 |
| 3 | 10 | 20 | LIMIT 20, 10 |
| n | size | (n-1)*size | LIMIT (n-1)*size, size |
LIMIT 9, -1會報錯,無法實現「從第10條到結尾」LIMIT 1000000, 10需掃描前100萬行再丟棄,極其低效ORDER BY列建立索引,避免filesortORDER BY列順序及排序方向WHERE與ORDER BY列組合可用聯合索引方案A:延遲關聯(適合InnoDB主鍵聚簇索引)
-- 1. 只查主鍵ID(覆蓋索引,極快)
SELECT id FROM huge_table ORDER BY id LIMIT 1000000, 10;
-- 2. 應用層拿到ID列表,再回表查詳情
SELECT * FROM huge_table WHERE id IN (id1, id2, ...);
方案B:游標/記憶最大值(適合遞增ID、時間戳)
-- 首頁
SELECT * FROM posts WHERE id > 0 ORDER BY id LIMIT 20;
-- 記錄最後一條ID = 100
-- 下一頁
SELECT * FROM posts WHERE id > 100 ORDER BY id LIMIT 20;
避免OFFSET,利用索引範圍查詢,性能穩定。
方案C:覆蓋索引+子查詢
SELECT * FROM huge_table
WHERE id >= (SELECT id FROM huge_table ORDER BY id LIMIT 1000000, 1)
ORDER BY id LIMIT 10;
當確定結果唯一(如登錄驗證),加LIMIT 1:
SELECT * FROM user WHERE username='admin' AND password='xxx' LIMIT 1;
命中第一條即停止掃描,顯著提升效率。
<?php
$page = max(1, intval($_GET['page']));
$size = 20;
$offset = ($page - 1) * $size;
// 1. 總數查詢(可緩存、異步、近似值)
$total = $pdo->query("SELECT COUNT(*) FROM articles WHERE status=1")->fetchColumn();
// 2. 數據查詢(延遲關聯優化)
$ids = $pdo->query("
SELECT id FROM articles
WHERE status=1
ORDER BY created_at DESC
LIMIT $offset, $size
")->fetchAll(PDO::FETCH_COLUMN);
if ($ids) {
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$stmt = $pdo->prepare("
SELECT id, title, summary, created_at
FROM articles
WHERE id IN ($placeholders)
ORDER BY created_at DESC
");
$stmt->execute($ids);
$articles = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 3. 輸出分頁信息
$totalPages = ceil($total / $size);
// ... 渲染分頁導航
?>
| 場景 | 推薦寫法 | 避坑指南 |
|---|---|---|
| 首頁/前幾頁 | LIMIT offset, size | offset較小時可接受 |
| 深分頁(>10萬) | 延遲關聯 / 游標ID / 覆蓋索引子查詢 | 嚴禁大OFFSET直查 |
| 無序分頁 | 必須加ORDER BY | 無ORDER BY結果不可控 |
| 唯一查找 | LIMIT 1 | 節省全表掃描 |
| 排序列無索引 | 建立索引或接受filesort | 大數據量filesort極慢 |
掌握ORDER BY與LIMIT的底層機制與優化模式,是構建流暢用戶體驗、降低數據庫負載的關鍵技能。