Skip to content

Commit bcc0a52

Browse files
committed
增加111 关键字
1 parent 5befbfa commit bcc0a52

File tree

30 files changed

+389
-0
lines changed

30 files changed

+389
-0
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
---
2+
title: 一次显著的MySQL大表分页查询优化,从2.35s到18ms!
3+
shortTitle: 从2.35秒到18毫秒,这次显著的MySQL大表分页查询优化,深得leader称赞
4+
description: 大表分页查询非常慢,怎么办?
5+
author: 鸭血粉丝Tang
6+
category:
7+
- 微信公众号
8+
head:
9+
---
10+
11+
>[二哥的编程星球](https://mp.weixin.qq.com/s/e5Q4aJCX9xccTzBBGepx4g)已经有 **910 多名** 球友加入了,如果你也需要一个良好的学习氛围,[戳链接](https://mp.weixin.qq.com/s/e5Q4aJCX9xccTzBBGepx4g)加入我们吧!这是一个Java学习指南+编程实战+LeetCode 刷题的私密圈子,你可以向二哥提问、帮你制定学习计划、和球友一起打卡成长,冲冲冲。
12+
13+
## 一、问题复现
14+
15+
在实际的软件系统开发过程中,随着使用的用户群体越来越多,表数据也会随着时间的推移,单表的数据量会越来越大。
16+
17+
以订单表为例,假如每天的订单量在 4 万左右,那么一个月的订单量就是 120 多万,一年就是 1400 多万,随着年数的增加和单日下单量的增加,订单表的数据量会越来越庞大,**订单数据的查询不会像最初那样简单快速,如果查询关键字段没有走索引,会直接影响到用户体验,甚至会影响到服务是否能正常运行**
18+
19+
下面我以某个电商系统的**客户表**为例,**数据库是 Mysql,数据体量在 100 万以上,详细介绍分页查询下,不同阶段的查询效率情况**(订单表的情况也是类似的,只不过它的数据体量比客户表更大)。
20+
21+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-6a0fd06b-595b-4a70-b79c-008ec25f3ebb.jpg)
22+
23+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-4c405350-b5c2-4a98-b919-1b01f2d97045.jpg)
24+
25+
下面我们一起来测试一下,每次查询客户表时最多返回 100 条数据,不同的起始下,数据库查询性能的差异。
26+
27+
* **当起点位置在 0 的时候,仅耗时:18 ms**
28+
29+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-23a24b41-14ca-4371-bdd6-b0ae7288d58d.jpg)
30+
31+
* **当起点位置在 1000 的时候,仅耗时:23 ms**
32+
33+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-21f287ff-0c00-47ad-8625-db80b9f89839.jpg)
34+
35+
* **当起点位置在 10000 的时候,仅耗时:54 ms**
36+
37+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-a2aae7d6-3def-4430-bd2a-23fcd2cbd02a.jpg)
38+
39+
* **当起点位置在 100000 的时候,仅耗时:268 ms**
40+
41+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-743791f9-6133-4203-ad67-40f22ff60032.jpg)
42+
43+
* **当起点位置在 500000 的时候,仅耗时:1.16 s**
44+
45+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-7dc4ce81-5052-4cfc-822e-cfb00fee9de7.jpg)
46+
47+
* **当起点位置在 1000000 的时候,仅耗时:2.35 s**
48+
49+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-2d5c5c66-c30d-4a4a-b025-0ca4d9d4fb76.jpg)
50+
51+
可以非常清晰的看出,随着起点位置越大,分页查询效率成倍的下降,当起点位置在 1000000 以上的时候,对于百万级数据体量的单表,查询耗时基本上以秒为单位。
52+
53+
而事实上,**一般查询耗时超过 1 秒的 SQL 都被称为慢 SQL**,有的公司运维组要求的可能更加严格,比如小编我所在的公司,如果 SQL 的执行耗时超过 0.2s,也被称为慢 SQL,**必须在限定的时间内尽快优化,不然可能会影响服务的正常运行和用户体验**
54+
55+
对于千万级的单表数据查询,小编我刚刚也使用了一下分页查询,**起点位置在 10000000,也截图给大家看看,查询耗时结果:39 秒**
56+
57+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-4d690fe6-78b4-44a5-979e-1e483ad62ac4.jpg)
58+
59+
没有接触过这么大数据体量的同学,可能多少对这种查询结果会感到吃惊,事实上,这还只是数据库层面的耗时,还没有算后端服务的处理链路时间,以及返回给前端的数据渲染时间,以百万级的单表查询为例,如果数据库查询耗时 1 秒,再经过后端的数据封装处理,前端的数据渲染处理,以及网络传输时间,没有异常的情况下,差不多在 3~4 秒之间,可能有些同学对这个请求时长数值还不太敏感。
60+
61+
据互联网软件用户体验报告,当平均请求耗时在1秒之内,用户体验是最佳的,此时的软件也是用户留存度最高的;2 秒之内,还勉强过的去,用户能接受;当超过 3 秒,体验会稍差;超过 5 秒,基本上会卸载当前软件。
62+
63+
有的公司为了提升用户体验,会严格控制请求时长,当请求时长超过 3 秒,自动放弃请求,从而倒逼技术优化调整 SQL 语句查询逻辑,甚至调整后端整体架构,比如引入缓存中间件 redis,搜索引擎 elasticSearch 等等。
64+
65+
继续回到我们本文所需要探讨的问题,**当单表数据量到达百万级的时候,查询效率急剧下降,如何优化提升呢**
66+
67+
## 二、解决方案
68+
69+
> 下面我们一起来看看具体的解决办法。
70+
71+
#### 2.1、方案一:查询的时候,只返回主键 ID
72+
73+
我们继续回到上文给大家介绍的客户表查询,将`select *`改成`select id`,简化返回的字段,我们再来观察一下查询耗时。
74+
75+
* **当起点位置在 100000 的时候,仅耗时:73 ms**
76+
77+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-0db3dbe4-8333-41d3-860e-00d5a9bdcb26.jpg)
78+
79+
* **当起点位置在 500000 的时候,仅耗时:274 ms**
80+
81+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-408e85b8-3ee6-4135-a470-baf01f7c41b0.jpg)
82+
83+
* **当起点位置在 1000000 的时候,仅耗时:471 ms**
84+
85+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-88755ad9-ec59-44ae-8f4b-8dcfb06abb7c.jpg)
86+
87+
可以很清晰的看到,**通过简化返回的字段,可以很显著的成倍提升查询效率**
88+
89+
实际的操作思路就是先通过分页查询满足条件的主键 ID,然后通过主键 ID 查询部分数据,可以显著提升查询效果。
90+
91+
```
92+
-- 先分页查询满足条件的主键ID
93+
select id from bizuser order by id limit 100000,10;
94+
95+
-- 再通过分页查询返回的ID,批量查询数据
96+
select * from bizuser where id in (1,2,3,4,.....);
97+
```
98+
99+
#### 2.2、方案二:查询的时候,通过主键 ID 过滤
100+
101+
这种方案有一个要求就是主键ID,**必须是数字类型,实践的思路就是取上一次查询结果的 ID 最大值,作为过滤条件,而且排序字段必须是主键 ID,不然分页排序顺序会错乱**
102+
103+
* **查询 100000~1000100 区间段的数据,仅耗时:18 ms**
104+
105+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-6442c1c1-65ac-4227-a68d-fb1f7e07210a.jpg)
106+
107+
* **查询 500000~5000100 区间段的数据,仅耗时:18 ms**
108+
109+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-458734b4-95b9-4a42-bcf6-cb0d6cf8bdf7.jpg)
110+
111+
* **查询 1000000~1000100 区间段的数据,仅耗时:18 ms**
112+
113+
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/nice-article/weixin-yicxzdmysqldbfyzxyhcsdms-150548d9-a12d-4207-91bc-2855b76c2152.jpg)
114+
115+
可以很清晰的看到,带上主键 ID 作为过滤条件,查询性能非常的稳定,基本上在`20 ms`内可以返回。
116+
117+
**这种方案还是非常可行的,如果当前业务对排序要求不多,可以采用这种方案,性能也非常杠**
118+
119+
**但是如果当前业务对排序有要求,比如通过客户最后修改时间、客户最后下单时间、客户最后下单金额等字段来排序,那么上面介绍的【方案一】,比【方案二】查询效率更高**
120+
121+
#### 2.3、方案三:采用 elasticSearch 作为搜索引擎
122+
123+
当数据量越来越大的时候,尤其是出现分库分表的数据库,以上通过主键 ID 进行过滤查询,效果可能会不尽人意,例如订单数据的查询,**这个时候比较好的解决办法就是将订单数据存储到 elasticSearch 中**,通过 elasticSearch 实现快速分页和搜索,效果提升也是非常明显。
124+
125+
关于 elasticSearch 的玩法,以后有机会再给大家介绍。
126+
127+
## 三、小结
128+
129+
不知道大家有没有发现,**上文中介绍的表主键 ID 都是数值类型的,之所以采用数字类型作为主键,是因为数字类型的字段能很好的进行排序**
130+
131+
但如果当前表的主键 ID 是字符串类型,比如 uuid 这种,就没办法实现这种排序特性,而且搜索性能也非常差,因此不建议大家采用 uuid 作为主键ID,具体的数值类型主键 ID 的生成方案有很多种,比如自增、雪花算法等等,都能很好的满足我们的需求。
132+
133+
134+
* * *
135+
136+
137+
没有什么使我停留——除了目的,纵然岸旁有玫瑰、有绿荫、有宁静的港湾,我是不系之舟。
138+
139+
- [先不管那么多,offer接了再说](https://mp.weixin.qq.com/s/9f_sOLiRwDS3pzC-mJ9jLQ)
140+
- [假如我是核酸系统架构师](https://mp.weixin.qq.com/s/24rup4Jkch7ELdtI_l-yZg)
141+
- [一套KTV管理系统,估价3万还是30万?](https://mp.weixin.qq.com/s/zYLEUmbfmiKeFk03e1TxbA)
142+
- [撸一个多线程永动任务](https://mp.weixin.qq.com/s/6z06U97fmrkKB-J1umFTVQ)
143+
- [本次秋招最差面试体验给到华为!](https://mp.weixin.qq.com/s/wfp8LBPPxHE_CM4d3wARQw)
144+
- [给offer的公司不问技术细节?](https://mp.weixin.qq.com/s/QYFB2NHhyZSBfdgSUcZU5g)
145+
- [入职一个月,就想跑路了?](https://mp.weixin.qq.com/s/SfEUk-4hE6ezUk2Lu6cd2g)
146+
- [3 个令你耳目一新的练手项目](https://mp.weixin.qq.com/s/CdIin5I7VvfaSk4z9J0FwQ)
147+
148+
149+
150+
151+
152+
153+
154+
155+
156+
157+
![](https://img-blog.csdnimg.cn/img_convert/61f1d83899ac533c2b892a3e39f09fdc.png)

docs/sidebar/sanfene/collection.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ CopyOnWriteArrayList采用了一种读写分离的并发策略。CopyOnWriteArra
123123

124124
![CopyOnWriteArrayList原理](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/collection-7.png)
125125

126+
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
127+
128+
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
129+
126130
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
127131

128132
## Map
@@ -687,4 +691,8 @@ if (e != null) { // existing mapping for key
687691

688692
> 图文详解 30 道Java集合框架面试高频题,这次吊打面试官,我觉得稳了(手动 dog)。整理:沉默王二,戳[转载链接](https://mp.weixin.qq.com/s/ptbM0EqlnCWeWm9VdSCDLg),作者:三分恶,戳[原文链接](https://mp.weixin.qq.com/s/SHkQ7LEOT0itt4bXMoDBPw)
689693
694+
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
695+
696+
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
697+
690698
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)

docs/sidebar/sanfene/javase.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ Java 语言既具有编译型语言的特征,也具有解释型语言的特征
8181

8282
![编译与解释](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javase-5.png)
8383

84+
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
85+
86+
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
87+
8488
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
8589

8690
## 基础语法
@@ -246,6 +250,10 @@ int autoAdd(int count)
246250

247251
PS:笔试面试可能会碰到的奇葩题,开发这么写,见一次吊一次。
248252

253+
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
254+
255+
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
256+
249257
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
250258

251259
## 面向对象
@@ -517,6 +525,10 @@ Java 中有以下四种创建对象的方式:
517525

518526
前两者都需要显式地调用构造方法。对于 clone 机制,需要注意浅拷贝和深拷贝的区别,对于序列化机制需要明确其实现原理,在 Java 中序列化可以通过实现 Externalizable 或者 Serializable 来实现。
519527

528+
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
529+
530+
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
531+
520532
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
521533

522534
## String
@@ -631,6 +643,10 @@ JDK 源码里已经对这个方法进行了说明:
631643
- 如果当前字符串内容存在于字符串常量池(即 equals()方法为 true,也就是内容一样),直接返回字符串常量池中的字符串
632644
- 否则,将此 String 对象添加到池中,并返回 String 对象的引用
633645

646+
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
647+
648+
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
649+
634650
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
635651

636652
## Integer
@@ -731,6 +747,10 @@ public static int parseInt(String s, int radix)
731747

732748
![parseInt示意图](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javase-20.png)
733749

750+
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
751+
752+
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
753+
734754
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
735755

736756
## Object
@@ -1402,6 +1422,10 @@ reduced.ifPresent(System.out::println);
14021422

14031423
----
14041424

1425+
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
1426+
1427+
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
1428+
14051429
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
14061430

14071431
> 图文详解 53 道Java基础面试高频题,这次吊打面试官,我觉得稳了(手动 dog)。整理:沉默王二,戳[转载链接](https://mp.weixin.qq.com/s/t7EYyF0VGEg1rAZut9dwSw),作者:三分恶,戳[原文链接](https://mp.weixin.qq.com/s/M-6RSRcRd3X93cR7VXpanw)

0 commit comments

Comments
 (0)