MySQL分页查询的工作原理

  1. 前言
    MySQL 的分页查询在我们的开发过程中还是很常见的,比如一些后台管理系统,我们一般会有查询订单列表页、商品列表页等。

示例:

SELECT * FROM goods order by create_time limit 0,10;
在了解order by和limit的工作原理之前,我们首先回顾下 MySQL 的执行流程和索引结构。

注: 下面没有特别说明默认 MySQL 的引擎为 InnoDB 为讲述方便使用 select * ,生产环境不建议使用
1.1. 执行流程
在这里插入图片描述
MySQL 可以分为 Server 层和存储引擎层两部分,对于这个就不展开讲了。只需要知道一条 SQL 语句是从客户端发起请求到 Server 层,Server 层处理之后选出成本最低的执行计划去存储引擎层进行数据查询,查询出来的数据返回给 Server 层处理,最后返回给客户端。(存储引擎层根据扫描区间定位拿到数据给到 Server 层,剩下的过滤、排序、分页等操作是在 Server 层载进行处理的)。

1.2 索引结构

在这里插入图片描述
InnoDB 存储引擎的索引是一颗 B+ 树,只有主键索引树会存储全部的行记录数据,二级索引只会存储该记录对应的主键 id。所以我们使用二级索引查询数据时,如果查询的字段在二级索引没办法完全覆盖,则需要回表。

  1. order by 工作原理
    准备工作
    创建一张商品表,并且给价格字段设置索引
REATE TABLE goods (id BIGINT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(255) NOT NULL comment '商品名称',price DECIMAL(10,2) NOT NULL comment '售价',create_time  DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '创建时间',update_time  DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
);
create index idx_price on goods (price);

插入测试数据

delimiter $$
DROP PROCEDURE IF EXISTS proc_batch_insert;
CREATE PROCEDURE proc_batch_insert()
BEGINDECLARE pre_name BIGINT;DECLARE priceVal INT;DECLARE i INT;SET pre_name=1;SET priceVal=30;SET i=1;WHILE i < 1000000 DOINSERT INTO goods(`name`,price,create_time,update_time) VALUES(CONCAT('商品',pre_name),(priceVal+i)%100,NOW(),NOW());SET pre_name=pre_name+1;SET i=i+1;END WHILE;
END $$delimiter ;
call proc_batch_insert();

2.1 索引扫描排序
EXPLAIN SELECT * FROM goods where price > 10 and price < 13 ORDER BY price;
图片

我们发现这条 sql 使用了索引 idx_price,索引结构如下:
在这里插入图片描述
首先会根据二级索引idx_price进行查询找到满足price > 10 and price < 13区间的主键值,因为我们的查询条件是SELECT *,所以需要回表查询到对应的行记录。由于ORDER BY price,我们是需要对查询出来的结果按照价格从小到大进行排序。我们刚刚的数据就是从二级索引idx_price查询出来的,本就是根据price字段排序的,所以无需再排序,直接把查询的数据返回给客户端就行了。
在这里插入图片描述
2.2 文件排序(filesort)
以下 3条 sql 语句都会使用文件排序

-- Using where; Using filesort
EXPLAIN SELECT * FROM goods where price > 10 and price < 30 ORDER BY price;
-- Using where; Using filesort
EXPLAIN SELECT * FROM goods where name like '商品 1%' ORDER BY price;
-- Using index condition; Using filesort
EXPLAIN SELECT * FROM goods where price > 10 and price < 13 ORDER BY name;

对于第二条 sql ,我们很容易判断出来,使用不了二级索引idx_price,只能全表扫描查询出符合条件的行记录再去进行文件排序。

那么第一条 sql 只是查询范围比之前的更大了,为什么就不走二级索引了呢?

我们前面介绍执行流程时说道:MySQL 会选择执行成本最低的执行计划。这条 sql 的查询范围是price > 10 and price < 30,满足这个条件的数据是很多的,每一条数据都需要进行回表查询。这样大量的回表查询,MySQL 认为是很慢的,所以没有使用二级索引。

第三条 sql 虽然可以使用到二级索引idx_price,但是需要排序的字段是name,那么二级索引的作用就只是帮助我们加快查询,而排序操作还是需要使用文件排序。

什么是文件排序呢?

文件排序分成两种:全字段排序、rowid 排序。接下来,我们分别讲解这两种排序工作原理。

2.2.1 全字段排序
MySQL 会给每个线程分配一块内存用于排序 sort_buffer。sort_buffer_size,就是 MySQL 为排序开辟内存(sort_buffer)的大小。

如果要排序的数据量小于 sort_buffer_size,排序就在内存中完成。但如果排序数据量太大,内存放不下,则不得不利用磁盘临时文件来辅助排序。

EXPLAIN SELECT * FROM goods where price > 10 and price < 13 ORDER BY name;

在这里插入图片描述
我们根据这条 sql 来分析查询过程:

先根据二级索引idx_price查询出满足过滤条件的数据

根据主键 id 进行回表操作查询出对应的行记录

数据汇总到 sort_buffer 按照name进行排序

将排序好的结果集返回给客户端

2.2.2 rowid 排序
我们发现全字段排序会存在一个问题:如果表中的字段非常多,我们把整个行记录放入 sort_buffer 里面进行排序时,能够放入的行记录就会很少,排序性能差。

max_length_for_sort_data ,是 MySQL 中专门控制用于排序的行数据的长度的一个参数。它的意思是,如果单行的长度超过这个值,MySQL 就认为单行太大,要换一个算法。使用 rowid 排序:需要排序的字段 + 主键 id 放入 sort_buffer 进行排序。

在这里插入图片描述
还是使用上述 sql 分析:

可以使用二级索引,所以先根据二级索引idx_price查询出满足过滤条件的数据
根据主键 id 进行回表操作查询出对应的行记录
将排序字段name和主键 id 一起放入 sort_buffer 进行排序
根据主键 id 再去主键索引查询全部字段返回给客户端
如果 MySQL 实在是担心排序内存太小,会影响排序效率,才会采用 rowid 排序算法,这样排序过程中一次可以排序更多行,但是需要再回到原表去取数据。如果 MySQL 认为内存足够大,会优先选择全字段排序,把需要的字段都放到 sort_buffer 中,这样排序后就会直接从内存里面返回查询结果了,不用再回到原表去取数据。

这也就体现了 MySQL 的一个设计思想:如果内存够,就要多利用内存,尽量减少磁盘访问。

对于 InnoDB 表来说,rowid 排序要求回表多造成磁盘读,因此不会被优先选择。

2.2.3 排序算法
我们前面说在 sort_buffer 进行排序,但是没有说明具体是什么排序算法,其实我们这个排序算法是需要分情况的,具体如下:

若排序内容能全部放入内存,则仅在内存中使用快速排序;
若排序内容不能全部放入内存,则分批次将排好序的内容放入文件,然后将多个文件进行归并排序
若排序中包含 limit 语句,则使用堆排序优化排序过程
3. limit 工作原理
Server 层维护了一个称作 limit_count 的变量用于统计已经跳过了多少条记录。limit m , n 工作原理就是先读取前面 m+n 条记录,然后抛弃前 m条,读后面 n条想要的,所以 m越大,偏移量越大,性能就越差。

EXPLAIN SELECT * FROM goods where price > 10 and price < 13 ORDER BY name limit 500,10;

如上述 sql 语句,MySQL 先查询 510 条数据,按照ORDER BY的工作原理进行条件查询和排序,最后汇总的结果在返回给客户端之前,MySQL 会截取第 501 到 510 条数据,最后把这 10 行记录返回给前端。

  1. 常见问题分析
    4.1 排序字段使用非唯一字段导致乱序问题
    我们平常使用的分页查询,如果没有用到索引排序底层的排序算法是堆排序,由于是堆排序是不稳定排序,会产生乱序问题。

分页查询商品表,根据创建时间进行排序
SELECT * FROM goods order by create_time limit 0,10;
但是如果此时数据库的商品数据都是通过 Excel 导入进去的,那么它们的创建时间都是一样的,那就会乱序。
在这里插入图片描述

在这里插入图片描述
5 个商品的顺序是不一定的(堆排序:不稳定排序),当我们从第一页到第二页时,商品 3又到了第一页。

那么我们就一直找不到商品 3。对于这个问题,我们可以改成按照主键 id 排序。

4.2 深度分页问题

SELECT * FROM goods ORDER BY price LIMIT 80000,10

在这里插入图片描述

这样的 sql 就是深度分页了,我们之前讲到,MySQL 的底层会查询出 80010 条数据进行文件排序(因为查询数量太多,回表次数过多,MySQL 便不使用二级索引),然后再截取第 80001 到 第80010 条数据返回给客户端。

要解决这种深度分页问题首先应该在产品的设计方面避免这种情况,还有就是我们在查询分页数据时应该需要根据时间做好限制,减少数据,以及对前端传进来的 start、limit 字段进行判断限制。如果还是需要深度分页,就需要利用子查询来实现。

SELECT * FROM goods g
INNER JOIN
(SELECT id FROM goods ORDER BY price LIMIT 80000,10) AS d
ON g.id=d.id;

在这里插入图片描述
子查询使用二级索引查出满足条件的主键,然后进行分页过滤出我们需要主键 id,再去主键索引查询数据(因为排序字段就是我们的二级索引字段,所以查询出来的数据直接就是有序的,无需再进行文件排序)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/145656.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python | 机器学习之逻辑回归

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《人工智能奇遇记》&#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 目录结构 1. 机器学习之逻辑回归概念 1.1 机器学习 1.2 逻辑回归 2. 逻辑回归 2.1 实验目的…

开发一款小程序游戏需要多少钱?

小程序游戏的开发成本因多种因素而异&#xff0c;无法提供具体的固定数字。以下是影响小程序游戏开发成本的一些关键因素&#xff1a; 游戏规模和复杂度&#xff1a; 小程序游戏可以是简单的休闲游戏&#xff0c;也可以是更复杂的策略游戏。规模和复杂度会影响开发所需的时间和…

字节跳动小程序开发:探索创新的数字化世界

在数字化时代&#xff0c;字节跳动小程序开发成为企业数字化转型的关键一环。通过这一平台&#xff0c;企业能够借助先进的技术和丰富的功能&#xff0c;实现创新、引领市场潮流。本文将通过一些简单的技术代码示例&#xff0c;带你深入了解字节跳动小程序开发的魅力。 1. 小…

科研学习|研究方法——python T检验

一、单样本T检验 目的&#xff1a;检验单样本的均值是否和已知总体的均值相等前提条件&#xff1a; &#xff08;1&#xff09;总体方差未知&#xff0c;否则就可以利用 Z ZZ 检验&#xff08;也叫 U UU 检验&#xff0c;就是正态检验&#xff09;&#xff1b; &#xff08;2&a…

Android SmartTable根据int状态格式化文字及颜色

private void initData() {List<UserInfo> list new ArrayList<>();list.add(new UserInfo("一年级", "李同学", 6, 1, 120, 1100, 450, 0));list.add(new UserInfo("一年级", "张同学", 6, 2, 120, 1100, 450, 1));list…

工业数据采集分析 数据跨层次、跨环节、跨系统大整合

在“工业4.0”、“智能制造”、“工业互联网”的大背景下&#xff0c;数据采集早就成为一个广泛关注的热点话题&#xff0c;不论智能制造发展到何种程度&#xff0c;数据采集都是生产过程中应用非常频繁的需求&#xff0c;也是工业物联网不可或缺的一环。 利用工业数据采集系统…

处理机器学习数据集中字符串列(pandas.get_dummies)

如图&#xff0c;在数据集中week列的数据不是数值型&#xff0c;会导致我们在训练过程中难以处理。 而pandas库中有一个非常好用的函数&#xff0c;独热编码pandas.get_dummies(df) 使用此函数之后&#xff0c;会在原数据中新建各列代表Fri-Sun&#xff0c;值为0或1&#xff…

【大话Presto 】- 核心概念

文章目录 前言Operator Model And Iterator Model系统组成Connector数据模型查询执行模型StatementStageTaskSplitDriverOperatorExchangePipeLine 总结 前言 Presto&#xff08;PrestoDB&#xff09;是一个FaceBook开源的分布式MPP SQL引擎&#xff0c;旨在处理大规模数据的查…

全新的FL studio21.2版支持原生中文FL studio2024官方破解版

FL studio2024官方破解版是一款非常专业的音频编辑制作软件。目前它的版本来到了全新的FL studio21.2版&#xff0c;支持原生中文&#xff0c;全面升级的EQ、母带压线器等功能&#xff0c;让你操作起来更加方便&#xff0c;该版本经过破解处理&#xff0c;用户可永久免费使用&a…

「校园 Pie」 系列活动正式启航,首站走进南方科技大学!

PieCloudDB 社区校园行系列活动「校园 Pie」已正式启动。「校园 Pie」旨在促进数据库领域的学术交流&#xff0c;提供一个平台让学生们了解最新的数据库发展趋势和相关技术应用。 在「校园 Pie」系列活动中&#xff0c;PieCloudDB 社区将携拓数派技术专家&#xff0c;社区大咖…

可以免费使用的设计素材网站分享

UI设计师最怕什么&#xff1f; 没有创意&#xff0c;没有灵感&#xff0c;没有思路&#xff01; 在哪里可以得到idea&#xff1f;别担心&#xff0c;往下看&#xff01; 你知道网络有多大&#xff0c;你想要什么吗&#xff1f;今天&#xff0c;我想和大家分享一些宝藏网页设…

用户运营:如何搭建用户分析体系

在运营的工作范畴中&#xff0c;用户运营是很重要的一个环节&#xff0c;甚至有公司会设置专门的“用户运营”岗位。 用户运营的价值体现在多个方面&#xff0c;不仅可以帮助引流、吸引更多用户使用产品&#xff0c;在用户正式使用产品之后的运营则更为重要。通过日常用户运营&…

SpringMVC调用流程

SpringMVC的调用流程 SpringMVC涉及组件理解&#xff1a; DispatcherServlet : SpringMVC提供&#xff0c;我们需要使用web.xml配置使其生效&#xff0c;它是整个流程处理的核心&#xff0c;所有请求都经过它的处理和分发&#xff01;[ CEO ] HandlerMapping : SpringMVC提供&…

第四代智能井盖传感器:万宾科技助力城市安全

在繁华喧嚣的城市里人来人往&#xff0c;井盖作为基础设施的一个组成部分在路面上分布范围广。然而这些看似普通的井盖却存在着位移、水浸的风险&#xff0c;可能给我们的生活带来诸多不便&#xff0c;更会威胁到我们的人身安全。如何有效监测和管理井盖的状态&#xff0c;成为…

为什么选择CodeEase?

目录 为什么选择CodeEase核心功能后端前端 框架结构总结 为什么选择CodeEase CodeEase是一个标准化的低代码平台 愿景 我们励志开发一站式服务&#xff0c;缩短网站开发周期&#xff0c;降低程序bug率&#xff0c;减少开发人力和成本&#xff0c;推出了多租户SaaS平台开发模板…

SpringCloud Alibaba组件入门全方面汇总(上):注册中心-nacos、负载均衡-ribbon、远程调用-feign

文章目录 NacosRibbonFeignFeign拓展 Nacos 概念&#xff1a;Nacos是阿里巴巴推出的一款新开源项目&#xff0c;它是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos致力于帮助用户发现、配置和管理微服务&#xff0c;它提供了一组简单易用的特性集&am…

电源地虚接,导致信号线发烫

音频板的信号是经过隔直电容接到音频板的。

【Linux专题】firewalld 过滤出接口流量

【赠送】IT技术视频教程&#xff0c;白拿不谢&#xff01;思科、华为、红帽、数据库、云计算等等_厦门微思网络的博客-CSDN博客文章浏览阅读428次。风和日丽&#xff0c;小微给你送福利~如果你是小微的老粉&#xff0c;这里有一份粉丝福利待领取...如果你是新粉关注到了小微&am…

智慧工地解决方案,实现安全预警、机械智能监控、作业指导、绿色施工、劳务管理、工程进度监控、施工质量检查

智慧工地云平台全套源码 智慧工地平台采用先进的云计算、物联网和大数据技术&#xff0c;可以实现智慧工地方案的落地。能够实现实时掌控工地活动及各项进度&#xff0c;有效预防违章施工。能够为工地提供多项服务&#xff0c;如安全预警、机械智能监控、作业指导、绿色施工、劳…

JVM bash:jmap:未找到命令 解决

如果我们在使用JVM的jmap命令时遇到了"bash: jmap: 未找到命令"的错误&#xff0c;这可能是因为jmap命令没有在系统的可执行路径中。 要解决这个问题&#xff0c;可以尝试以下几种方法&#xff1a; 1. 检查Java安装&#xff1a;确保您已正确安装了Java Development …