排序查询(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 |
重点小结
-
不加 order by,查询结果顺序是不确定的,不要依赖默认顺序;
-
asc:升序,默认;desc:降序; -
单字段排序:只根据
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;
执行规则(重点)
- 优先按第一个字段
age desc:年龄从大到小排- age=20(最大)→ age=19 → age=18
- 只有第一个字段的值相等时,才启用第二个字段
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页
排序逻辑:
- 优先按 score 从大到小;
- 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;
✔️总结
- 分页
order by字段必须保证排序组合唯一,重复字段后面追加主键; - 不要只靠非唯一字段排序分页,会丢数据、重复;
- 大 offset 深度分页,不要直接
limit 大偏移量,条数,优先书签分页优化。