Administrator
Administrator
发布于 2026-10-27 / 0 阅读
0
0

数据库入门到初级(09):排序与分页:商品列表是怎么查出来的

数据库入门到初级 · 第 09/22 篇。实验口径:MySQL 8.4、InnoDB、utf8mb4。案例:小型商城。

商城列表常有“价格从低到高”和“下一页”。这两项功能分别依赖排序和分页。真正容易出错的地方不是语法,而是价格相同怎么排、翻页期间数据变化怎么办。

1. ORDER BY 指定结果顺序

SELECT id, name, price FROM products
ORDER BY price ASC, id ASC;

ASC 表示升序,DESC 表示降序。样例升序结果是:数据线 29、无线鼠标 89、笔记本支架 129、机械键盘 199、旧款耳机 299。

如果只写 ORDER BY price,价格相同的行之间没有被完整指定顺序。追加唯一编号 id,可以让同价商品也有明确先后。不要用插入顺序或今天的查询输出代替排序规则。

从有序列表到分页结果

多个排序字段分别指定方向。例如 ORDER BY created_at DESC, id DESC 适合“最新在前”;不要误以为一个末尾的 DESC 会自动作用于前面的全部字段。

2. LIMIT 与 OFFSET

SELECT id, name, price FROM products
ORDER BY price ASC, id ASC
LIMIT 2 OFFSET 0;

SELECT id, name, price FROM products
ORDER BY price ASC, id ASC
LIMIT 2 OFFSET 2;

第一页是数据线、无线鼠标,第二页是笔记本支架、机械键盘。OFFSET 是跳过多少条,不是页码。每页大小为 page_size 时,偏移量是 (page_number - 1) * page_size。

应用应限制页码和每页数量,避免用户请求一次返回几百万行。接口需要总数时,可以单独执行相同筛选条件下的 COUNT(*),不能直接把当前页条数当作全部数量。

3. 稳定排序也不能冻结数据

假设用户看完第一页后,另一个人新增了价格更低的商品。原来排第 2 的商品可能移动到第 3,第二页就可能再次看到它。反过来,删除前面的商品可能让后面的商品被跳过。

追加 id 解决同价商品排序不确定的问题,但不会冻结翻页过程中的整个数据集。是否需要一致快照,取决于业务:普通商品浏览常能接受变化,结算报表通常要求更严格的口径。

4. 游标分页的基本思想

如果页面只需要“下一页”,可以记住上页最后一件商品的 (price, id)。第一页末尾是价格 89、编号 2,则下一页查询:

SELECT id, name, price FROM products
WHERE price > 89.00
   OR (price = 89.00 AND id > 2)
ORDER BY price ASC, id ASC
LIMIT 2;

结果仍是笔记本支架、机械键盘。它表达“从这个排序位置之后继续找”,避免逐页累积很大的偏移量。要获得理想性能,还需要结合合适的索引和执行计划判断。

游标分页也有边界:难以直接跳到任意页;排序字段被修改时,仍可能出现跨页位置变化。因此它不是所有分页问题的万能解法。

5. 两个常见误区

LIMIT 10 不等于“前十名”,因为没有排序就没有明确的“前”。“销量前十”还要先定义销量口径,是成交件数、订单数,还是退款后的净销量。

另外,OFFSET 100000 不一定只读取 10 行就完成。执行过程可能需要处理并跳过大量记录。遇到慢分页,要用执行计划和实际数据验证,不能只看返回结果有几行。

练习与答案

练习一:按最新订单在前,每页两条,查第一页。

SELECT id, created_at FROM orders
ORDER BY created_at DESC, id DESC
LIMIT 2;

结果为 1004、1003。

练习二:每页 20 条,第 3 页的 OFFSET 是多少? 是 40,不是 60。第一页不跳过记录。


上一篇:第 08 篇 · 系列目录 · 下一篇:第 10 篇


评论