写在前面
这是奇点云全新技术专栏「StartDT Tech Lab」的第12期。
在这里,我们聚焦数据技术,分享方法论与实战。一线的项目经历,丰富的实践经验,真实的总结体会。
本篇由奇点云高级Java开发工程师「张三」带来:
作者:张三
阅读时间:约5分钟
商品列表展示、新闻列表展示……无论什么类型的系统,只要有前端页面供用户操作,往往都有业务数据列表查询展示的功能。而这些列表展示的功能,通常都采用了分页查询的形式来实现。
之所以选择分页查询的方式,我认为至少有三点原因:
1. 分页查询更符合用户使用的习惯;
2. 这些业务数据放在一个页面显示的话,如果数据量太大,就会无法正常显示;
3. 即便假设页面足够大,受限于系统服务及所使用的数据库配置,也是无法一次获取和处理太多数据的。
通过上面的介绍,大家了解到,如果需要商品列表查询,可以使用分页查询来做。那么问题来了:
如果遇到上千万或者上亿的数据需要同步,比如我们的DataNuza系统的圈人结果数据,原始数据是存放在大数据的库中,而应用系统直接拿这个库来使用的话,十分不方便,且存在性能问题,所以我们需要将数据同步到应用数据库中。
本次主要分享我们在大数据同步方面优化分页查询的经验。
方案 1
一般分页查询
以MySQL为例,一般的分页查询使用简单的 limit 子句就可以实现。limit 子句声明如下:
# 第一个参数n指定第一个返回记录行的偏移量,第二个参数m指定返回记录行的最大数目。SELECT c1,c2,… FROM table LIMIT n,m;
MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行。那当offset特别大的时候,效率就会非常低下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。
方案 2
基于主键id实现分页查询优化
假设数据表的id是连续递增的,则我们根据查询的页数和查询的记录数可以算出查询的id的范围,尽量给出查询的大致范围。
SELECT c1,c2,cn... FROM table WHERE id>=50000 LIMIT 10;
←左滑查看
这种查询方式能够极大地优化查询速度,基本能在几十毫秒之内完成。
限制则是只能用于明确知道id的情况。不过一般建立表的时候,都会添加基本的id字段,这为分页查询带来很多便利。
方案 3
利用表的覆盖索引来加速分页查询
我们都知道,利用了索引查询的语句中如果只包含了那个索引列(覆盖索引),那么这种情况会查询很快。
因为利用索引查找有优化算法,且数据就在查询索引上面,不用再去找相关的数据地址了,这样节省了很多时间。
另外MySQL中也有相关的索引缓存,在并发高的时候利用缓存就效果更好了。
在我们的例子中,我们知道id字段是主键,自然就包含了默认的主键索引。
select * from test t inner join (
select id from test limit 5000000,10
) tt on t.id = tt.id;
方案 4
分表分库
尽管上面的方法可以优化查询的速度,但数据表的数据量超过500W的时候,还是建议使用分表分库,将数据拆分到不同的表中,减少数据行和索引的量也会大幅度提高查询效率。但这种方法要求源表做出改变,不一定适用所有的场景。
以上就是本次分享的分页查询优化经验。
在实际项目中,我们采用了基于主键id实现分页查询优化,同步的过程中,记录下每次同步的主键id,作为下一轮同步的限定id,也做了程序异常退出恢复机制。
希望能给大家提供一些帮助和思路,欢迎大家一起交流,共同进步!