MySQL深分页问题解决思路


Posted in MySQL onDecember 24, 2022

一、MySQL深分页问题

我们在日常开发中,查询数据量比较大的时候,后端基本都会通过前端,移动端传过来的页码,每页数据行数,通过SQL中的 limit 进行分页,如果查询页数比较小的时候,不会出现太大问题,但是如果查询页码比较大的时候,性能就会出现急剧下降瓶颈

如:

假设有一个千万量级的表,取1到10条数据

select column_name1,column_name2... from table limit 0,10;
select column_name1,column_name2... from table limit 1000,10;

这两条语句查询时间应该在毫秒级完成

select column_name1,column_name2... from table limit 1000000,10;

这条语句执行之间在秒级完成,查询效率低下,还可能导致接口超时

使用select column_name1,column_name2... from table_name表名 limit offset, rows 的情况下直接⽤limit 1000000,10 扫描的是约100万条数据,并且是需要回表100W次,也就是说⼤部分性能都耗在随机访问上,到头来只⽤到10条数据(总共取1000010条数据只留10条记录)

这种查询的慢,其实是因为 limit 后面的偏移量太大导致的

1、limit 语法解读

limit用于数据的分页查询,也会用于数据的截取,limit的用法:

SELECT column_name1,column_name2... FROM table_name表名 LIMIT offset,rows
或
SELECT column_name1,column_name2... FROM table_name表名 LIMIT rows OFFSET offset

注:

table_name :表名

column_name:字段名

第一种:SELECT * FROM table LIMIT offset, rows # 常用形式

-- 从0开始,截取5条记录,即检索行为1到5
SELECT column_name1,column_name2... FROM table_name表名 limit 0,5
-- 注意: 关键字limit后面的两个参与用逗号分割

第二种:SELECT * FROM table LIMIT rows OFFSET offset

-- 从0开始,截取5条记录,即检索行为1到5
SELECT column_name1,column_name2... FROM table_name表名 limit 5 offset 0
-- 注意: 使用limit和offset两个关键字,并且各带一个参数,中间没有逗号分割

第三种:SELECT * FROM table LIMIT rows

-- 截取记录的前五行数据,可以理解为offset的默认值为0
SELECT column_name1,column_name2... FROM table_name表名 limit 5

2、回表

回表,顾名思义就是回到表中,也就是先通过普通索引扫描出数据所在的行,再通过行主键ID取出索引中未包含的数据。所以回表的产生也是需要一定条件的,如果一次索引查询就能获得所有的select记录就不需要回表,如果select所需获得列中有其他的非索引列,就会发生回表动作。即基于非主键索引的查询需要多扫描一棵索引树

主键索引树的叶子节点直接就是我们要查询的整行数据,而非主键索引的叶子节点是主键的值,查到主键的值以后,还需要再通过主键的值再进行一次查询

回表,简单说就是mysql内部需要经过两次查询

第一次先索引扫描,然后再通过主键去取索引中未能提供的数据

create `table` tb_name(
    `id` int(11) not null auto_increment , 
    `k` int(11) default '0' ,
    `name` varchar(16),
    primary key(id)
    index (k)
)engine=InnoDB;

我们提取id=500这一行的全部数据,这里通过主键id定位到这一行,然后返回数据

select * from T where ID=500;
+-----+---+-------+
| id  | k | name  |
+-----+---+-------+
| 500 | 5 | name5 |
+-----+---+-------+

这里我们先通过普通索引,搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程即为回表

select * from T where k=5;
+-----+---+-------+
| id  | k | name  |
+-----+---+-------+
| 500 | 5 | name5 |
+-----+---+-------+

二、优化方案

(一)模仿百度、谷歌方案(前端业务控制)

MySQL深分页问题解决思路

类似于分段。我们给每次只能翻100页、超过一百页的需要重新加载后面的100页。这样就解决了每次加载数量数据大 速度慢的问题了

这种方式比较简单粗暴,就是不允许查看这么靠后的数据

(二)索引覆盖 + 子查询

根据主键 id,在上面建了索引,先在索引树中找到开始位置的 id 值,再根据找到的 id 值查询行数据

SELECT 
    id,name,age 
FROM
    t_user user
WHERE
    user.id = (select MIN(id) from t_user where age = #{age})
SELECT 
    id,name,age 
FROM 
    t_user 
WHERE 
    id >= (SELECT id FROM t_user order by id LIMIT 80000,1) 
LIMIT 10

(三)起始位置重定义(记录每次取出的最大id, 然后where id > 最大id)

这种方法适用于:除了主键ID等离散型字段外,也适用连续型字段datetime等

最大id由前端分页 pageNum 和 pageIndex 计算出来

select * from table_name Where id > 最大id limit 10000, 10;

到此这篇关于MySQL深分页问题解决思路的文章就介绍到这了,更多相关MySQL深分页内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
MySQL时间设置注意事项的深入总结
May 06 MySQL
教你解决往mysql数据库中存入汉字报错的方法
May 06 MySQL
Mysql官方性能测试工具mysqlslap的使用简介
May 21 MySQL
SQL注入的实现以及防范示例详解
Jun 02 MySQL
MySql 缓存查询原理与缓存监控和索引监控介绍
Jul 02 MySQL
MySQL令人大跌眼镜的隐式转换
Aug 23 MySQL
Mysql存储过程、触发器、事件调度器使用入门指南
Jan 22 MySQL
Linux系统下MySQL配置主从分离的步骤
Mar 21 MySQL
为什么MySQL不建议使用SELECT *
Apr 03 MySQL
mysql中关键词exists的用法实例详解
Jun 10 MySQL
MySQL实现字段分割一行转多行的示例代码
Jul 07 MySQL
MySQL count(*)统计总数问题汇总
Sep 23 MySQL
DQL数据查询语句使用示例
Dec 24 #MySQL
mysql数据库如何转移到oracle
Dec 24 #MySQL
mysql序号rownum行号实现方式
Dec 24 #MySQL
Mysql的Table doesn't exist问题及解决
Dec 24 #MySQL
Mysql如何查看是否使用到索引
Dec 24 #MySQL
MySQL新手入门进阶语句汇总
Sep 23 #MySQL
MySQL下载安装配置详细教程 附下载资源
Sep 23 #MySQL
You might like
不用数据库的多用户文件自由上传投票系统(3)
2006/10/09 PHP
How do I change MySQL timezone?
2008/03/26 PHP
利用php递归实现无限分类 格式化数组的详解
2013/06/08 PHP
destoon实现VIP排名一直在前面排序的方法
2014/08/21 PHP
PHP制作用户注册系统
2015/10/23 PHP
基于Laravel5.4实现多字段登录功能方法示例
2017/08/11 PHP
Laravel使用支付宝进行支付的示例代码
2017/08/16 PHP
php 读写json文件及修改json的方法
2018/03/07 PHP
PHP+MariaDB数据库操作基本技巧备忘总结
2018/05/21 PHP
JavaScript写的一个自定义弹出式对话框代码
2010/01/17 Javascript
JavaScript实现找出字符串中第一个不重复的字符
2014/09/03 Javascript
BootStrap 智能表单实战系列(二)BootStrap支持的类型简介
2016/06/13 Javascript
Vue.js用法详解
2017/11/13 Javascript
vue.js2.0 实现better-scroll的滚动效果实例详解
2018/08/13 Javascript
Node.js中读取TXT文件内容fs.readFile()用法
2018/10/10 Javascript
node app 打包工具pkg的具体使用
2019/01/17 Javascript
js 实现 list转换成tree的方法示例(数组到树)
2019/08/18 Javascript
vue滚动插件better-scroll使用详解
2019/10/18 Javascript
vue穿梭框实现上下移动
2021/01/29 Vue.js
python3操作mysql数据库的方法
2017/06/23 Python
python cx_Oracle的基础使用方法(连接和增删改查)
2017/11/19 Python
对变量赋值的理解--Pyton中让两个值互换的实现方法
2017/11/29 Python
django 实现电子支付功能的示例代码
2018/07/25 Python
HTML5的结构和语义(4):语义性的内联元素
2008/10/17 HTML / CSS
英国最大的女士服装零售商:Bonmarché
2017/08/17 全球购物
Cinque网上商店:德国服装品牌
2019/03/17 全球购物
英国高街奥特莱斯:Highstreet Outlet
2019/11/21 全球购物
圣彼得堡鲜花配送:Semicvetic
2020/09/15 全球购物
费用会计岗位职责
2014/01/01 职场文书
《孔子游春》教学反思
2014/02/25 职场文书
三分钟演讲稿范文
2014/04/24 职场文书
爱国演讲稿400字
2014/05/07 职场文书
2016年社区党支部公开承诺书
2016/03/25 职场文书
python引入其他文件夹下的py文件具体方法
2021/05/23 Python
MySQL系列之五 视图、存储函数、存储过程、触发器
2021/07/02 MySQL
Python MNIST手写体识别详解与试练
2021/11/07 Python