首页 > 数据库 >MySQL Limit 分页查询优化

MySQL Limit 分页查询优化

时间:2024-10-07 10:12:52浏览次数:7  
标签:语句 分页 MySQL 查询 Limit SQL limit 主键

前言

在各类系统的表格类信息展示的功能中,经常会用到“翻页”这个操作,在页面上每次只展示有限的数据,需要看其他数据的时候则像翻书一样翻到后面的“页”。

在 MySQL支持的 SQL 语法中对此有特殊的支持,开发人员在实现这类功能的时候很方便:

  • select * from xxx limit M,N
  • select * from xxx limit N offset M

这两类语法代表的意思是一样的:返回从第 M 开始(不包括这一行)之后的 N 行数据。虽然使用起来很方便,但是这类语句存在查询性能上的陷阱,需要特别注意一下。

原理简介

在解释原理之前,先看一下实际的效果,看看这个“性能的陷阱”是什么。

性能效果图

两个语句的内容都非常简单,差别只在 limit 的部分,第一个语句跳过的行数很少,第二个语句跳过的行数很多,结果是两个语句的执行时间差了至少 200 倍。

PS:limit 配合 order by 使用是一个好习惯,确保结果数据是稳定的

可以看到跳过的行数大幅度增长时,SQL 语句的执行时间也会快速增长,原因其实比较简单:在处理 limit M,N 的时候,MySQL 会先拿到 M+N 行结果数据,然后再丢弃 M 行数据,展示之后剩下的 N 行数据。

所以上图的第二个语句实际上扫描了 800 多万行数据,然后丢弃了 800 万行数据,只展示之后的 1 行结果。

explain 和 optimizer_trace 都看不出来差别,但是 profile 里面能看出来两者的差距:

profile 结果

虽然都只输出一行结果,但是在 Sending data 阶段花费的时间差别很大,其实就是花在扫描 800 万行数据上去了。

优化策略

针对这个问题,其实有一个比较通用的优化思路:利用 join,先根据主键搜索到需要的数据,再通过主键关联到原来的表输出结果。

SQL 可以改写一下:

SQL 改写的效果

可以看到查询时间降到了 1.5s 左右,提升了约 37%,看起来还可以,那么还有其他的办法么?

显然还是有的,不过这会要求表有自增主键。

在分页查询的时候,记录上一次查询结果中的主键,然后在 where 条件中添加主键的范围约束

以上面的查询为例,上次分页查询时的主键是 8000001,那么下次分页的时候,where 条件中添加一个主键约束:id > 8000001,再来看看查询效果:

添加条件之后的效果

可以发现利用主键来筛选掉上一次分页前的所有数据后再用 limit,查询基本是马上返回结果的。

不过要特别注意,这种方法是根据主键的顺序先做了一次筛选,不一定会适用于所有的业务场景,理论上 UUID 类的主键也可以用,但是改造 SQL 前务必确保查询结果是符合预期的

总结一下

MySQL 由于本身查询优化器覆盖到的场景不够全,慢查询的原因也千奇百怪,各类业务 SQL 在上线前尽量多覆盖一些场景,确保业务功能安全发布。

标签:语句,分页,MySQL,查询,Limit,SQL,limit,主键
From: https://www.cnblogs.com/shujuyr/p/18449791

相关文章

  • MySQL gh-ost 工具使用详解
    前言MySQL的同步机制比较单纯,主库上执行过的DML和DDL会在从库上再执行一次,那么主库上需要10min才能执行完的DDL理论上在从库至少也要花费10min才能执行完,这意味着从库的同步会延迟10min以上,等DDL执行完之后才会继续追同步。解决方案从MySQL的同步原理来看,主要......
  • MySQL 大表改列
    前言作为一个MySQLDBA,和大表打交道的次数想必不少,大表上的ALTER操作一般影响都很大,平时会用OnlineDDL工具来辅助操作,但是本文会介绍一种特殊的技巧来应对一部分大表上的ALTER需求。解决方案从标题可以看出来,这次会用到MySQL5.7的新功能:GeneratedColumn,这种虚拟列......
  • mysql数据库连接异常问题(总结)
    针对你提到的多种数据库连接问题,下面进行总结和建议,以避免未来再次遇到相同的问题:1.连接超时(AnattemptbyaclienttocheckoutaConnectionhastimedout)原因:网络不稳定数据源配置参数异常解决方案:优化网络环境:检查网络延迟和丢包率。考虑使用更稳定的网络......
  • 连接Mysql时出现的“no database selected”错误该如何解决?
    遇到“nodatabaseselected”错误通常是因为在尝试执行SQL查询时没有明确指定要使用的数据库。以下是解决这个问题的步骤:确认连接时已选择数据库在连接数据库之后,确保已经选择了具体的数据库。例如,在MySQL中,可以使用 USE<database_name>; 语句来选择一个数据库。USE......
  • MySQL遇到问题及解决方案
    针对MySQL遇到的问题及解决方案,可以按照以下步骤进行排查和解决:查看错误日志查看MySQL的日志文件,特别是error.log文件。命令行下可以通过 tail-f/var/lib/mysqlhostname.err 查看实时日志。检查数据库服务状态确认MySQL服务是否正在运行。bash systemctl......
  • 探索MySQL的InnoDB索引失效
    MySQL8+InnoDB- 序章索引失效,发生在已经建立索引,但是,查询(SELECT)时没有用到建立的(预期会用到)索引的情况下。失效原因有两个方面:1、建立索引的方式错误需要弄清楚 字段的#区分度(极其重要)这个概念。选择区分度高的建立索引。2、某些SELECT语句不支持使用索引注意,......
  • MySQL单表存多大的数据量比较合适
    前言经常使用MySQL数据库的小伙伴都知道,当单表数据量达到一定的规模以后,查询性能就会显著降低。因此,当单表数据量过大时,我们往往要考虑进行分库分表。那么如何计算单表存储多大的数据量合适?当单表数据达到多大的规模时,我们才要进行分库分表呢?MySQL存储方式首先我们要先了解一下......
  • 【2024计算机毕业设计】基于jsp+mysql+Spring+mybatis的SSM药品进货销售仓储信息管理
    运行环境:最好是javajdk1.8,我在这个平台上运行的。其他版本理论上也可以。IDE环境:Eclipse,Myeclipse,IDEA或者SpringToolSuite都可以,如果编译器的版本太低,需要升级下编译器,不要弄太低的版本tomcat服务器环境:Tomcat7.x,8.x,9.x版本均可操作系统环境:WindowsXP/7......
  • 分页使用示例
    1.代码classUserModelSerializer(serializers.ModelSerializer):role_display=UserRoleSerializer(many=True,source='roles',read_only=True)classMeta:model=models.Userfields=["id","username",&#......
  • [MySQL]为什么大厂选择读已提交
    为什么读已提交的并发性更好在数据库中,锁的时间和范围是影响并发性的重要因素。已提交读(ReadCommitted)隔离级别与可重复读(RepeatableRead)的主要区别就在于它们在读取数据时对锁的使用方式不同。让我们详细看看为什么已提交读的锁的时间和范围更小。1.已提交读(ReadCommitte......