Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >面试官:数据量很大,分页查询很慢,有什么优化方案?

面试官:数据量很大,分页查询很慢,有什么优化方案?

作者头像
程序员鹏磊
发布于 2019-12-10 09:53:42
发布于 2019-12-10 09:53:42
1.1K00
代码可运行
举报
文章被收录于专栏:架构师专栏架构师专栏
运行总次数:0
代码可运行

当需要从数据库查询的表有上万条记录的时候,一次性查询所有结果会变得很慢,特别是随着数据量的增加特别明显,这时需要使用分页查询。对于数据库分页查询,也有很多种方法和优化的点。下面简单说一下我知道的一些方法。

准备工作

为了对下面列举的一些优化进行测试,下面针对已有的一张表进行说明。

1、表名:order_history 2、描述:某个业务的订单历史表 3、主要字段:unsigned int id,tinyint(4) int type 4、字段情况:该表一共37个字段,不包含text等大型数据,最大为varchar(500),id字段为索引,且为递增。 5、数据量:5709294 6、MySQL版本:5.7.16

线下找一张百万级的测试表可不容易,如果需要自己测试的话,可以写shell脚本什么的插入数据进行测试。

以下的 sql 所有语句执行的环境没有发生改变,下面是基本测试结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select count(*) from orders_history;

返回结果:5709294

三次查询时间分别为:

  • 8903 ms
  • 8323 ms
  • 8401 ms

一般分页查询

一般的分页查询使用简单的 limit 子句就可以实现。limit 子句声明如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset

LIMIT 子句可以被用于指定 SELECT 语句返回的记录数。需注意以下几点:

1、第一个参数指定第一个返回记录行的偏移量,注意从0开始 2、第二个参数指定返回记录行的最大数目 3、如果只给定一个参数:它表示返回最大的记录行数目 4、第二个参数为 -1 表示检索从某一个偏移量到记录集的结束所有的记录行 5、初始记录行的偏移量是 0(而不是 1)

下面是一个应用实例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select * from orders_history where type=8 limit 1000,10;

该条语句将会从表 orders_history 中查询offset: 1000开始之后的10条数据,也就是第1001条到第1010条数据(1001 <= id <= 1010)。

数据表中的记录默认使用主键(一般为id)排序,上面的结果相当于:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select * from orders_history where type=8 order by id limit 10000,10;

三次查询时间分别为:

  • 3040 ms
  • 3063 ms
  • 3018 ms

针对这种查询方式,下面测试查询记录量对时间的影响:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select * from orders_history where type=8 limit 10000,1;
select * from orders_history where type=8 limit 10000,10;
select * from orders_history where type=8 limit 10000,100;
select * from orders_history where type=8 limit 10000,1000;
select * from orders_history where type=8 limit 10000,10000;

三次查询时间如下:

1、查询1条记录:3072ms 3092ms 3002ms 2、查询10条记录:3081ms 3077ms 3032ms 3、查询100条记录:3118ms 3200ms 3128ms 4、查询1000条记录:3412ms 3468ms 3394ms 5、查询10000条记录:3749ms 3802ms 3696ms

另外我还做了十来次查询,从查询时间来看,基本可以确定,在查询记录量低于100时,查询时间基本没有差距,随着查询记录量越来越大,所花费的时间也会越来越多。整编:微信公众号,搜云库技术团队,ID:souyunku

针对查询偏移量的测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select * from orders_history where type=8 limit 100,100;
select * from orders_history where type=8 limit 1000,100;
select * from orders_history where type=8 limit 10000,100;
select * from orders_history where type=8 limit 100000,100;
select * from orders_history where type=8 limit 1000000,100;

三次查询时间如下:

1、查询100偏移:25ms 24ms 24ms 2、查询1000偏移:78ms 76ms 77ms 3、查询10000偏移:3092ms 3212ms 3128ms 4、查询100000偏移:3878ms 3812ms 3798ms 5、查询1000000偏移:14608ms 14062ms 14700ms

随着查询偏移的增大,尤其查询偏移大于10万以后,查询时间急剧增加。

这种分页查询方式会从数据库第一条记录开始扫描,所以越往后,查询速度越慢,而且查询的数据越多,也会拖慢总查询速度。

使用子查询优化

这种方式先定位偏移位置的 id,然后往后查询,这种方式适用于 id 递增的情况。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select * from orders_history where type=8 limit 100000,1;

select id from orders_history where type=8 limit 100000,1;

select * from orders_history where type=8 and 
id>=(select id from orders_history where type=8 limit 100000,1) 
limit 100;

select * from orders_history where type=8 limit 100000,100;

4条语句的查询时间如下:

  • 第1条语句:3674ms
  • 第2条语句:1315ms
  • 第3条语句:1327ms
  • 第4条语句:3710ms

针对上面的查询需要注意:

1、比较第1条语句和第2条语句:使用 select id 代替 select * 速度增加了3倍 2、比较第2条语句和第3条语句:速度相差几十毫秒 3、比较第3条语句和第4条语句:得益于 select id 速度增加,第3条语句查询速度增加了3倍

这种方式相较于原始一般的查询方法,将会增快数倍。

使用 id 限定优化

这种方式假设数据表的id是连续递增的,则我们根据查询的页数和查询的记录数可以算出查询的id的范围,可以使用 id between and 来查询:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select * from orders_history where type=2 
and id between 1000000 and 1000100 limit 100;

查询时间:15ms 12ms 9ms

这种查询方式能够极大地优化查询速度,基本能够在几十毫秒之内完成。限制是只能使用于明确知道id的情况,不过一般建立表的时候,都会添加基本的id字段,这为分页查询带来很多便利。

还可以有另外一种写法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select * from orders_history where id >= 1000001 limit 100;

当然还可以使用 in 的方式来进行查询,这种方式经常用在多表关联的时候进行查询,使用其他表查询的id集合,来进行查询:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select * from orders_history where id in
(select order_id from trade_2 where goods = 'pen')
limit 100;

这种 in 查询的方式要注意:某些 mysql 版本不支持在 in 子句中使用 limit。

使用临时表优化

这种方式已经不属于查询优化,这儿附带提一下。

对于使用 id 限定优化中的问题,需要 id 是连续递增的,但是在一些场景下,比如使用历史表的时候,或者出现过数据缺失问题时,可以考虑使用临时存储的表来记录分页的id,使用分页的id来进行 in 查询。这样能够极大的提高传统的分页查询速度,尤其是数据量上千万的时候。整编:微信公众号,搜云库技术团队,ID:souyunku

关于数据表的id说明

一般情况下,在数据库中建立表的时候,强制为每一张表添加 id 递增字段,这样方便查询。

如果像是订单库等数据量非常庞大,一般会进行分库分表。这个时候不建议使用数据库的 id 作为唯一标识,而应该使用分布式的高并发唯一 id 生成器来生成,并在数据表中使用另外的字段来存储这个唯一标识。

使用先使用范围查询定位 id (或者索引),然后再使用索引进行定位数据,能够提高好几倍查询速度。即先 select id,然后再 select *;

本人才疏学浅,难免犯错,若发现文中有错误遗漏,望不吝赐教。

敬请关注「搜云库技术团队」微信公众号,获取最新文章

版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知我们,我们会立即删除并表示歉意。谢谢!

作者:悠悠

来源:dwz.cn/xU3nHQhO

如果对本文的内容有疑问,请在文章留言区留言,谢谢。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-07-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
大数据量性能优化之分页查询
刷帖子翻页需要分页查询,搜索商品也需分页查询。当遇到上千万、上亿数据量,怎么快速拉取全量数据呢? 比如:
JavaEdge
2021/10/18
6990
大数据量下的分页查询优化技巧
使用 select id 代替 select * 速度增加了3倍 这种方式假设数据表的id是连续递增的
韩旭051
2021/07/08
1.2K0
网页中分页的数据查询
有些网页中通常会有一个分页的样式,点击上一页或者下一页或者是具体的某一页的页码,页面中可以显示具体的从数据库查询的对应的数据。
马克社区
2022/04/11
7370
java mysql 分页_mysql分页查询总结
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
全栈程序员站长
2022/09/12
4.2K0
ES分页看这篇就够了
我们使用mysql的时候经常遇到分页查询的场景,在mysql中使用limit关键字来实现分页。比如下面的示例。
用户7634691
2020/08/10
25.5K0
mysql分页查询实例_mysql分页查询实例讲解「建议收藏」
LIMIT子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1)。下面,我们针对特例对mysql分页查询进行总结。
全栈程序员站长
2022/07/27
3.4K0
mysql大数据量分页查询优化总结
传统分页查询:SELECT c1,c2,cn… FROM table LIMIT n,m
全栈程序员站长
2022/07/19
1.6K0
MySQL - 分页查询优化的两个案例解析
任何一个系统,分页查询都是必不可少的吧 ,MySQL中的分页查询 就是 limit呗 ,你有没有感觉到 越往后翻页越慢 ,常见的SQL如下
小小工匠
2021/08/17
1.4K0
MySQL 百万级数据量分页查询方法及其优化
方法5: 利用MySQL支持ORDER操作可以利用索引快速定位部分元组,避免全表扫描
lyb-geek
2019/06/28
8080
千万的数据,你是怎么查询的?
代码创建一千万?那是不可能的,太慢了,可能真的要跑一天。可以采用数据库脚本执行速度快很多。
陈不成i
2021/06/08
7160
Java性能调优--SQL篇:优化"分页查询"
但在大数据量的情况下,分页查询是否存在效率问题?怎样分析SQL效率?如何优化分页查询效率?
浩说编程
2021/08/17
1.3K0
Java性能调优--SQL篇:优化"分页查询"
【我在拉勾训练营学技术】mysql 索引面试再也不怕啦
mysql 索引我们在面试是必问的,刚好我在拉勾训练营学习了 mysql 索引的相关知识,这里整理下来,自己对MySQL 索引有了全面了理解,面试的时候再也不怕啦。
程序员爱酸奶
2020/09/23
6970
【我在拉勾训练营学技术】mysql 索引面试再也不怕啦
浅谈MySQL分页查询
MySQL系列文章到目前已经更新十几篇,从数据类型谈到了备份恢复再到主从同步分库分表,从本篇开始,会花几篇重点谈谈MySQL基础部分,而本篇我们重点来讲讲我们日常开发中最常见的一种查询:分页查询。
创译科技
2019/10/29
3.9K0
浅谈MySQL分页查询
这真的不是八股!经典 MySQL 大数据量查询分页问题
正常情况下没有问题,但是当数据量非常大的时候,首先 count(*) 会非常慢这是肯定的,其次分页越多,limit 的效率就会越低。
飞天小牛肉
2024/02/01
6940
这真的不是八股!经典 MySQL 大数据量查询分页问题
分页查询 offset 和 limit 和 limit 的区别
select * from table limit 0,1000; select * from table limit 1000 offset 0;
袁新栋-jeff.yuan
2020/08/26
3.2K0
面试题-Mysql大表如何优化分页查询
分页查询是一个常用的功能,当单表数据量达到百万级别,查询速度缓慢,那么如何优化呢?
别明天就今天吧
2020/09/07
1.3K0
深分页怎么导致索引失效了?提供6种优化的方案!
在MySQL的limit中:limit 100,10MySQL会根据查询条件去存储引擎层找到前110条记录,然后在server层丢弃前100条记录取最后10条
菜菜的后端私房菜
2024/06/21
6671
MySQL具体解释(19)———-海量数据分页查询优化
查看代码打印1 SELECT * FROM table ORDER BY id LIMIT 1000,10; 以上SQL语句在原理上和在实际操作中是不会存在什么问题,可是当table表的数据量达到几十万以上的时候。上面的语句运行一遍,可能会要运行个十几秒的时间,而且当页数越靠后的话,运行的时间会越长。这个时候我们就须要找到一种更快的查询办法来替代这样的操作了。
全栈程序员站长
2022/01/28
1.2K0
相关推荐
大数据量性能优化之分页查询
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档