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 相关文章推荐
解决Navicat for Mysql连接报错1251的问题(连接失败)
May 27 MySQL
Mysql实现主从配置和多主多从配置
Jun 02 MySQL
探究Mysql模糊查询是否区分大小写
Jun 11 MySQL
Centos7中MySQL数据库使用mysqldump进行每日自动备份的编写
Aug 02 MySQL
MySQL数据库必备之条件查询语句
Oct 15 MySQL
详解MySql中InnoDB存储引擎中的各种锁
Feb 12 MySQL
MySQL中rank() over、dense_rank() over、row_number() over用法介绍
Mar 23 MySQL
MySQL表锁、行锁、排它锁及共享锁的使用详解
Apr 02 MySQL
Mysql 8.x 创建用户以及授予权限的操作记录
Apr 18 MySQL
MySQL 数据库 增删查改、克隆、外键 等操作
May 11 MySQL
MySQL索引失效场景及解决方案
Jul 23 MySQL
MySQL性能指标TPS+QPS+IOPS压测
Aug 05 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
通用PHP动态生成静态HTML网页的代码
2010/03/04 PHP
php生成短网址示例
2014/05/05 PHP
基于php编程规范(详解)
2017/08/17 PHP
PHP设计模式(五)适配器模式Adapter实例详解【结构型】
2020/05/02 PHP
javascript入门基础之私有变量
2010/02/23 Javascript
根据对象的某一属性进行排序的js代码(如:name,age)
2010/08/10 Javascript
jQuery为iframe的body添加click事件的实现代码
2011/04/07 Javascript
JavaScript XML和string相互转化实现代码
2011/07/04 Javascript
javascript原生和jquery库实现iframe自适应高度和宽度
2014/07/18 Javascript
JavaScript中Function函数与Object对象的关系
2015/12/17 Javascript
在Mac OS上安装使用Node.js的项目自动化构建工具Gulp
2016/06/18 Javascript
AngularJs $parse、$eval和$observe、$watch详解
2016/09/21 Javascript
Vue.js自定义指令的用法与实例解析
2017/01/18 Javascript
一道面试题引发的对javascript类型转换的思考
2017/03/06 Javascript
bootstrap警告框示例代码分享
2017/05/17 Javascript
深入研究React中setState源码
2017/11/17 Javascript
vue使用Google地图的实现示例代码
2018/12/19 Javascript
jQuery设置下拉框显示与隐藏效果的方法分析
2019/09/15 jQuery
js 执行上下文和作用域的相关总结
2021/02/08 Javascript
Python自定义scrapy中间模块避免重复采集的方法
2015/04/07 Python
Python实现批量下载图片的方法
2015/07/08 Python
Python文件和流(实例讲解)
2017/09/12 Python
用Python实现读写锁的示例代码
2018/11/05 Python
关于python下cv.waitKey无响应的原因及解决方法
2019/01/10 Python
python求最大值,不使用内置函数的实现方法
2019/07/09 Python
mac 上配置Pycharm连接远程服务器并实现使用远程服务器Python解释器的方法
2020/03/19 Python
Django def clean()函数对表单中的数据进行验证操作
2020/07/09 Python
纽约的奢华内衣店:Journelle
2016/07/29 全球购物
预订从美国飞往印度的机票:MyTicketsToIndia
2017/05/19 全球购物
澳大利亚在线划船、露营和钓鱼商店:BCF Australia
2020/03/22 全球购物
主要的Ajax框架都有什么
2013/11/14 面试题
初一家长会邀请函
2014/01/31 职场文书
学雷锋志愿者活动总结
2014/06/27 职场文书
2014年党的群众路线活动个人整改措施
2014/10/28 职场文书
研讨会通知
2015/04/27 职场文书
SpringCloud超详细讲解Feign声明式服务调用
2022/06/21 Java/Android