MySQL limit子句用法及优化(Limit Clause Optimization)

2024-06-19 20:12

本文主要是介绍MySQL limit子句用法及优化(Limit Clause Optimization),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在MySQL中,如果只想获取select查询结果的一部分,可以使用limit子句来限制返回记录的数量,limit在获取到满足条件的数据量时即会立刻终止SQL的执行。相比于返回所有数据然后丢弃一部分,执行效率会更高。

文章目录

  • 一、limit子句用法示例
    • 1.1 基本用法
    • 1.2 limit和order by
      • 1.2.1 排序瓶颈优化
  • 二、limit分页优化
    • 2.1 延迟关联
    • 2.2 转换为位置查询
    • 2.3 记录偏移位置

一、limit子句用法示例

limit子句通常放在select查询的最后,语法是limit [offset,] rowcount :

  • limit m,n 返回偏移量为m之后的n条数据,即先获取m+n条记录,然后丢弃前面的m条,返回之后的n条记录
  • limit n 返回开头的n条数据,相当于limit 0, n

1.1 基本用法

新建一张测试表并填充几条数据:

create table test(
id int auto_increment primary key,
name varchar(32),
salary decimal(10,2));insert into test values(null, 'aaa',1000),(null, 'bbb',2000),(null, 'ccc',3000),(null, 'ddd',4000),(null, 'eee',5000),(null, 'fff',6000),(null, 'ggg',7000),(null, 'hhh',8000),(null, 'iii',9000);

在这里插入图片描述

limit 0会立刻返回一个空结果集,它通常用来检测SQL语法是否正确或者快速获取结果集的字段属性。limit n用来返回最先获取的n条记录,找到足够的记录时SQL就会停止执行并返回结果:

select * from test limit 3;

在这里插入图片描述

采用limit m,n的形式,就是跳过前面的m条记录,返回之后的n条记录:

select * from test limit 3,3;

在这里插入图片描述

如果只是想跳过开头的m条记录,只需要给n一个足够大的数字即可,例如跳过开头100条记录:limit 100, 9999999999

1.2 limit和order by

如果order by子句和limit子句同时出现,那么MySQL会先对结果进行排序,对排序后的结果集应用limit子句。例如查询工资最高的3个人(按salary列倒序排列后取前3条记录):

select * from test order by salary desc limit 3;

在这里插入图片描述
如果排序的列存在重复数据,例如本例返回3条数据,但是3,4,5条记录的salary列都是相同的(它们都可以排在第三),这时返回的结果集是不确定的,查询时需注意。

1.2.1 排序瓶颈优化

与order by子句配合使用时,虽然limit子句最终获取的结果集可能很小,但需要先对所有的数据进行排序,如果这个数据量很大,那么排序操作就会成为性能瓶颈。

如果你发现limit子句加上order by之后语句执行很慢,可以尝试通过在排序列上增加索引来消除这个排序操作。由于示例表很小,优化器倾向于走全表扫描,这里找一张更大的表test1来演示,表中约有2万多条数据。观察添加索引前后的执行计划:

explain select * from test1 order by salary desc limit 3;
create index idx_salary on test1(salary);
explain select * from test1 order by salary desc limit 3;

在这里插入图片描述
可以看到索引反向扫描替代了原来的排序操作,同时扫描的行数量从24032降低到了3。

二、limit分页优化

limit子句最常用场景就是数据分页,通过变更偏移量来对数据进行分页展示。例如第一页显示100条数据,limit子句就是limit 0,100。第二页是limit 100,100,第三页是limit 200,100…. 但是当页数非常大时,limit m,n 中被丢弃的m条数据可能成为性能瓶颈。

由于前m条数据(偏移量)是最终需要的丢弃的,它们的内容我们并不关心,因此优化的思路就是"避免查询前m条数据的内容"。

2.1 延迟关联

为了避免查询偏移量m条数据的内容,我们可以先通过索引获取的n条数据的偏移量/主键(而不是对全量数据进行排序),然后通过主键直接获取n条数据的内容。这种策略叫做"延迟关联"。

例如查询:

select * from test1 order by salary desc limit 10000,100;

通过延迟关联可以改写为:

select salary from test1
join ( select id from test1 order by salary desc limit 10000,100) d on d.id=test1.id;

如果salary列上有索引,那么获取id是不需要回表的,通过索引就可以获取n条数据的主键,随后再与主表关联,通过主键取出这n条数据内容。虽然SQL看起来稍微复杂了,但是它绕过了获取前m条数据内容这个步骤,当m值比较大时,性能提升是很明显的。

2.2 转换为位置查询

这种策略是根据排序条件预先计算每行记录的顺序编号并加上索引,例如在表中新增一列position(或者单独新增一张顺序表也可以),保存的是每一行位置顺序。这相当于分页排序已经预先执行了,而偏移操作就被转换成了索引范围扫描。

例如查询:

select * from test1 order by salary desc limit 10000,100;

通过位置查询可以改写为:

select * from test1 where position between 10001 and 10100;

position列是根据order by salary desc条件预先维护好的每一列的顺序编号,此后每次分页查询都不需要计算偏移量,而是被转换成了索引范围扫描(Index Range Scan)。

2.3 记录偏移位置

记录偏移位置的方法,就是当排序列存在顺序的情况下,每次查询后将其最后的值记录下来,然后作为下一次SQL查询的过滤条件。

假设首次查询如下(id列单调递增):

select * from test1 order by id limit 9900,100;

假设上面查询返回结果集的最大id为123456,程序可以将这个值单独记录下来,那么SQL:

select * from test1 order by id limit 10000,100;

就可以改写为:

select * from test1 where id>123456 order by id limit 100;

通过条件where id>123456就可以过滤掉前m条数据,但这种方法的缺陷就是它只能一页一页的顺序往后翻,不能跳转翻页,对比上面2种方法不够灵活。

这篇关于MySQL limit子句用法及优化(Limit Clause Optimization)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1076030

相关文章

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Mysql表的简单操作(基本技能)

《Mysql表的简单操作(基本技能)》在数据库中,表的操作主要包括表的创建、查看、修改、删除等,了解如何操作这些表是数据库管理和开发的基本技能,本文给大家介绍Mysql表的简单操作,感兴趣的朋友一起看... 目录3.1 创建表 3.2 查看表结构3.3 修改表3.4 实践案例:修改表在数据库中,表的操作主要

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

一文详解SpringBoot响应压缩功能的配置与优化

《一文详解SpringBoot响应压缩功能的配置与优化》SpringBoot的响应压缩功能基于智能协商机制,需同时满足很多条件,本文主要为大家详细介绍了SpringBoot响应压缩功能的配置与优化,需... 目录一、核心工作机制1.1 自动协商触发条件1.2 压缩处理流程二、配置方案详解2.1 基础YAML

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

MySQL错误代码2058和2059的解决办法

《MySQL错误代码2058和2059的解决办法》:本文主要介绍MySQL错误代码2058和2059的解决办法,2058和2059的错误码核心都是你用的客户端工具和mysql版本的密码插件不匹配,... 目录1. 前置理解2.报错现象3.解决办法(敲重点!!!)1. php前置理解2058和2059的错误