排序和分⻚(order by 、limit)

排序查询(order by)

电商中:我们想查看今天所有成交的订单,按照交易额从⾼到低排序,此时我们可以使⽤ 数据库中的排序功能来完成。

语法:

复制代码
select 字段名 from 表名 order by 字段1 [asc|desc],字段2 [asc|desc];
  • order by:排序关键字,写在from之后
  • asc:升序(从小到大),默认值,可以省略不写
  • desc:降序(从大到小),必须显式写
  • 支持多字段排序 ,多个字段用逗号隔开; 规则:先按第一个字段排序,当第一个字段值相同时,才会按第二个字段排序

示例(电商订单场景)

1.查询订单,按交易额从高到低(降序)

复制代码
select id,amount from orders order by amount desc;

2.多字段排序:交易额降序,交易额相同的按下单时间升序

复制代码
select id,amount,create_time from orders order by amount desc,create_time asc;

补充要点:

1.order by是在where过滤之后执行;

复制代码
-- 先where筛选今天订单,再排序
select id,amount from orders where create_time >= '2026-10-08' order by amount desc;

2.没有指定排序字段时,数据库返回顺序是不确定的(物理存储顺序,不要依赖);

3.多字段排序每个字段都可以单独指定asc/desc,不是统一作用于全部字段。

单字段排序案例讲解

1.建表 & 插入数据

复制代码
-- 创建test2表,a是整数,b是字符串
create table test2(a int,b varchar(10));
-- 插入4条记录
insert into test2 values (10,'jack'),(8,'tom'),(5,'ready'),(100, 'javacode');

直接查询表,没有加 order by,返回顺序不一定有序,这里结果:

表格

a b
10 jack
8 tom
5 ready
100 javacode

2.升序 order by a asc

复制代码
select * from test2 order by a asc;

asc 从小到大排序(升序,默认可以省略不写) 结果:

表格

a b
5 ready
8 tom
10 jack
100 javacode

等价写法:select * from test2 order by a;

3.降序 order by a desc

复制代码
select * from test2 order by a desc;

desc 从大到小排序(降序,不能省略) 预期结果:

表格

a b
100 javacode
10 jack
8 tom
5 ready

重点小结

  1. 不加 order by,查询结果顺序是不确定的,不要依赖默认顺序;

  2. asc:升序,默认;desc:降序;

  3. 单字段排序:只根据order by后面这一个字段的值进行排序。

多字段排序 案例讲解

需求:学生表,先按年龄 age 降序;年龄相同的时候,再按学号 id 升序

1.建表 & 插入数据 SQL

复制代码
-- 创建学生表stu
create table stu(
  id int not null comment '学号' primary key,
  age tinyint not null comment '年龄',
  name varchar(16) comment '姓名'
);

-- 插入5条学生数据
insert into stu (id,age,name) values 
(1001,18,'路人甲Java'),
(1005,20,'刘德华'),
(1003,18,'张学友'),
(1004,20,'张国荣'),
(1010,19,'梁朝伟');

原始查询结果:

表格

id age name
1001 18 路人甲 Java
1003 18 张学友
1004 20 张国荣
1005 20 刘德华
1010 19 梁朝伟

2.多字段排序 SQL

复制代码
select * from stu order by age desc, id asc;

执行规则(重点)

  1. 优先按第一个字段 age desc :年龄从大到小排
    • age=20(最大)→ age=19 → age=18
  2. 只有第一个字段的值相等时,才启用第二个字段 id asc
    • age 都是 20 的两条:id 1004、1005,按学号升序 → 1004 在前,1005 在后
    • age 都是 18 的两条:id 1001、1003,按学号升序 →1001 在前,1003 在后

排序后最终结果

表格

id age name
1004 20 张国荣
1005 20 刘德华
1010 19 梁朝伟
1001 18 路人甲 Java
1003 18 张学友

✅ 核心要点

  • 多个排序字段用逗号隔开,顺序很重要! 从左往右依次判断;
  • 每个字段可以单独指定 asc / desc,互不影响;
  • 只有左边字段值相同,才会使用右边字段排序。

易错坑:不要以为写在最后的字段全局生效,它只是等值情况下的次级排序条件。

MySQL limit 知识点

语法

复制代码
select 列 from 表 limit [offset,] count;
  • offset:偏移量,跳过多少行,可选,默认 = 0;
  • count:跳过 offset 之后,取多少条记录;

⚠️注意:limit 后面只能写常量数字,不能写表达式。

1.limit n 等价于 limit 0,n:从第 0 行开始,取 n 条(获取前 n 行)

复制代码
-- 取前2条数据,下面两句效果完全一样
select * from t_order limit 2;
select * from t_order limit 0,2;

2.limit offset,count:跳过 offset 行,再取 count 行

复制代码
-- 跳过2行,取3条
select * from t_order limit 2,3;

分页公式(重点!开发常用)

第 page 页,每页 pageSize 条 limit (page-1)*pageSize , pageSize

示例:每页 2 条,查第 3 页

  • page=3,pageSize=2

  • offset = (3-1)*2 = 4

    select * from t_order limit 4,2;

案例

复制代码
-- 创建订单表
create table t_order(
    id int not null auto_increment comment '订单编号',
    price decimal(10,2) not null default 0 comment '订单金额',
    primary key(id)
)comment '订单表';

-- 插入测试数据
insert into t_order (price) values (88.95),(100.68),(500),(300),(20.88),(200.5);

表数据:

表格

id price
1 88.95
2 100.68
3 500.00
4 300.00
5 20.88
6 200.50
复制代码
-- 获取前2条记录
select * from t_order limit 2;

返回 id=1、id=2 的两条。

结合 order by 一起使用(非常重要)

实际分页一定要先排序,再 limit,否则分页数据会乱!

复制代码
-- 按价格降序,取前2条
select * from t_order order by price desc limit 2;

limit 执行顺序

select → from → where → order by → limit 先筛选、排序,最后才截取行数。

MySQL limit 分页查询详解

分页参数与公式

  • page:页码,从 1 开始
  • pageSize:每页多少条

偏移量公式:offset = (page - 1) * pageSize

复制代码
select 列 from 表名 limit offset, pageSize;

⚠️注意:MySQL limit 不能直接写表达式limit (page-1)*pageSize, pageSize,只能填计算后的常量数字,表达式要在代码里提前算好。

案例:订单表,按金额降序,每页 2 条

原始全量排序结果(order by price desc)

订单编号 id 订单金额 price
3 500.00
4 300.00
6 200.50
2 100.68
1 88.95
5 20.88

第 1 页(page=1,pageSize=2)

offset=(1-1)*2=0

复制代码
select a.id 订单编号,a.price 订单金额 from t_order a order by a.price desc limit 0,2;

返回:id3、id4

第 2 页(page=2,pageSize=2)

offset=(2-1)*2=2

复制代码
select a.id 订单编号,a.price 订单金额 from t_order a order by a.price desc limit 2,2;

返回:id6、id2

第 3 页(page=3,pageSize=2)

offset=(3-1)*2=4

复制代码
select a.id 订单编号,a.price 订单金额 from t_order a order by a.price desc limit 4,2;

返回:id1、id5

核心重点

✅ 分页必须搭配 order by! 如果不加order by,数据库返回行顺序不确定,分页会出现数据错乱、重复、丢失。

接下来就是分页经典坑:

当排序字段存在重复值 时,limit 分页会出现:同一数据出现在多页 / 部分数据消失。 原因:MySQL 对于相同排序值的行,返回顺序是随机的。 ✅解决方案:排序字段增加唯一字段(主键 id),保证排序结果唯一稳定。

示例修复写法:

复制代码
-- price降序,price相同则按id升序,保证顺序唯一
select a.id,a.price from t_order a order by a.price desc, a.id asc limit 0,2;

🚨 limit 分页经典坑:排序字段重复导致分页错乱

问题根源

当order by后面的字段存在多条相同值 时,MySQL 对这些相同值的行,没有固定排序规则,每次查询返回顺序随机。 分页时,就会出现:

  • 某一条数据在第 1 页、第 2 页重复出现
  • 某一条数据直接消失,翻页找不到

1.准备测试表和数据

复制代码
CREATE TABLE test_page (
  id INT PRIMARY KEY AUTO_INCREMENT,
  score INT COMMENT '分数'
);

INSERT INTO test_page(score)
VALUES (90),(90),(90),(80),(80),(70);

数据:

表格

id score
1 90
2 90
3 90
4 80
5 80
6 70

需求:按分数 score 降序,每页 2 条分页

2.有问题的 SQL(只按 score 排序)

复制代码
-- 错误写法:只按score排序,score有大量重复
select id,score from test_page order by score desc limit 0,2; -- 第1页
select id,score from test_page order by score desc limit 2,2; -- 第2页

现象演示

第一次查询:

  • 第 1 页:id1、id2
  • 第 2 页:id3、id4

MySQL 重启 / 索引优化后,再次执行相同 SQL,顺序变了!

  • 第 1 页:id2、id3
  • 第 2 页:id2、id4

👉 你会发现:id=2同时出现在第 1 页和第 2 页;id=1直接不见了。 因为 score 都是 90 的三条记录,数据库可以随机返回顺序,没有固定顺序。

3.修复方案:加上唯一字段(主键 id)做次级排序

核心:让order by组合条件全局唯一,每一行排序顺序固定不变。

复制代码
-- 正确写法:score降序,分数相同再按主键id升序
select id,score from test_page order by score desc, id asc limit 0,2; --第1页
select id,score from test_page order by score desc, id asc limit 2,2; --第2页
select id,score from test_page order by score desc, id asc limit 4,2; --第3页

排序逻辑:

  1. 优先按 score 从大到小;
  2. score 相同的时候,按主键 id 从小到大,主键永不重复,排序顺序永久固定。

稳定分页结果:

  • page1(limit 0,2): id1,id2
  • page2(limit 2,2): id3,id4
  • page3(limit 4,2): id5,id6

4.额外大坑:深度分页性能问题

当 offset 很大,比如limit 100000, 10 MySQL 会先读取前面 10 万条数据,丢弃,再取后面 10 条,越往后翻页越慢。

优化方案:主键 id 书签分页(where id > 上一页最大 id limit 10)

复制代码
-- 第一页
select id,score from test_page order by score desc,id asc limit 0,2;
-- 假设上一页最后一条id=2,下一页用id过滤
select id,score from test_page where id>2 order by score desc,id asc limit 2;

✔️总结

  1. 分页order by字段必须保证排序组合唯一,重复字段后面追加主键;
  2. 不要只靠非唯一字段排序分页,会丢数据、重复;
  3. 大 offset 深度分页,不要直接limit 大偏移量,条数,优先书签分页优化。
相关推荐
wdfk_prog1 小时前
LWIP教程 09:从 `tcp_slowtmr()` 到 Fast Retransmit——TCP 超时重传与重复 ACK
服务器·网络·数据库·网络协议·tcp/ip
逸模1 小时前
BIM在连锁餐饮装修中的应用:不只是画三维图
大数据·数据库·人工智能·物联网·建模
梦想平凡1 小时前
棋牌游戏技术实战(五):从对局事件重新执行规则,核对棋盘和最终状态
数据库·游戏·oracle
白露与泡影2 小时前
Oracle AI Database 26ai RAC 部署步骤、关键命令与一键脚本
数据库·人工智能·oracle
天天喝旺仔2 小时前
MySQL 索引原理与慢查询优化实战:从 B+ 树到执行计划调优
数据库·sql·mysql·性能优化
liulilittle2 小时前
Linux 下 select 测试函数
linux·服务器·网络·数据库·c++·select·c
DongQiShanRen3 小时前
玄龙(上):TICK 主循环——意识心跳怎么跳
linux·jvm·数据库·人工智能·数据挖掘·rust
数据库小学妹3 小时前
存算分离到底分离了什么?四条架构变化与选型判断
数据库·数据库架构·云原生数据库·缓存一致性·存算分离
FPGA小徐3 小时前
【一生一芯 / PA】异常响应机制:RISC-V 中 ecall → mtvec → mret 的完整代
开发语言·数据库·c#