问题的提出

我们知道,当我们的数据量达到一定数量时,需要将数据表进行水平拆分,从而满足大量数据的存储和查询,保证系统的可用性,但同时会出现另外一个问题就是,如果业务要查询“最近注册的第3页用户”,该如何实现呢?单库上,可以通过简单的sql实现分页查询。

select * from t_user order by time limit 200,100

1

select *fromt_userorderbytimelimit200,100

分库分表后变成两个库后,分库依据是user_id,排序依据是time,单个分数据库层失去了time排序的全局视野,如果同样需要实现分页查询时该怎么办呢?有什么比较好的MySQL分库分表的分页查询解决方案呢?

全局视野法

正常来讲,不管哪一个分库的第3页都不一定有全局第3页的所有数据,例如一下三种情况:

情况一:两个分库按照时间排序,数据各占一半,则每页取offset和limit的一般数据回来合并就可以了

情况二:所有数据都在一个库上,则取一个库的所有数据回来就可以了

情况三,那么一般情况是,每个分库的数据数据是随机的,但是一定是在全局offset=600之内

由于不清楚到底是哪种情况,所以必须每个库都返回3页数据,所得到的6页数据在服务层进行内存排序,得到数据全局视野,再取第3页数据,便能够得到想要的全局分页数据。

这种方法缺点是:当查询的页数增大时,每个分库所需返回的数据也越来成倍增加,降低了查询的性能

业务折中

第一种折中的方案是

对全局视野法的一种优化,即禁用制定页数的分页查询,必须通过下一页来实现分页查询的页数跳转,并且在每次查询下一页时将上一页的最大排序字段的值带上(这里就是时间time),这样在每个分库查询数据时待上这个条件,可以优化查询速率。

第二种折中的方案是

数据库分库-数据均衡原理

使用patition key进行分库,在数据量较大,数据分布足够随机的情况下,各分库所有非patition key属性,在各个分库上的数据分布,统计概率情况是一致的。

例如,在uid随机的情况下,使用uid取模分两库,db0和db1:

(1)性别属性,如果db0库上的男性用户占比70%,则db1上男性用户占比也应为70%

(2)年龄属性,如果db0库上18-28岁少女用户比例占比15%,则db1上少女用户比例也应为15%

(3)时间属性,如果db0库上每天10:00之前登录的用户占比为20%,则db1上应该是相同的统计规律

利用这一原理,要查询全局100页数据,offset 9900 limit 100改写为offset 4950 limit 50,每个分库偏移4950(一半),获取50条数据(半页),得到的数据集的并集,基本能够认为,是全局数据的offset 9900 limit 100的数据,当然,这一页数据的精度,并不是精准的。

根据实际业务经验,用户都要查询第100页网页、帖子、邮件的数据了,这一页数据的精准性损失,业务上往往是可以接受的,但此时技术方案的复杂度便大大降低了,既不需要返回更多的数据,也不需要进行服务内存排序了。

二次查找法

有没有一种方法既能满足业务要求,并且不需要折中,性能还高的方法呢?

接下来介绍一种“二次查找法”,不知道能不能讲的明白,我尽量吧。

为了方便举例,假设一页只有5条数据,查询第200页的SQL语句为select * from T order by time offset 1000 limit 5;

分五步:

1. 将select * from T order by time offset 1000 limit 5; 优化成select * from T order by time offset 500 limit 5,注意这里的500=1000/分表数量,并将这个sql下发至每个分库分表中执行,每个分库返回这个sql执行的结果。

2. 找到所有分库返回结果的time的最小值

第一个库,5条数据的time最小值是1487501123

第二个库,5条数据的time最小值是1487501223

故,三页数据中,time最小值来自第一个库,time_min=1487501123,这个过程只需要比较各个分库第一条数据,时间复杂度很低

3. 查询二次改写

第一次改写的SQL语句是select * from T order by time offset 500 limit 5

第二次要改写成一个between语句,between的起点是time_min,between的终点是原来每个分库各自返回数据的最大值:

第一个分库,第一次返回数据的最大值是1487501523

所以查询改写为select * from T order by time where time between time_min and 1487501523

第二个分库,第一次返回数据的最大值是1487501699

所以查询改写为select * from T order by time where time between time_min and 1487501699

从上面图片可以看出,DB1比第一次查出来的数据多了两行,应为查询的范围扩大了

4. 计算time_min这条记录在全局的offset

根据第一步查询的sqlselect * from T order by time offset 500 limit ,我们知道每个库的offset值了,将DB0中的最小time的数据虚拟到DB1中推算在DB1中的offset值=497

从而我们得知time_min这条记录在全局的offset值=500+497=997

5. 根据第二次查询出来的结果集,在内存中作排序,已知time_min在全局中的offset=997,那么结果集排序之后也能推算出offset=1000所在的记录,从而获得sqlselect * from T order by time offset 1000 limit 5的分页查询记录(图片黄色部分)

总结:可以精确的返回业务所需数据,每次返回的数据量都非常小,不会随着翻页增加数据的返回量。

浏览量:

7

0

MySQL分库分页_MySQL分库分表的分页查询解决方案相关推荐

  1. 分库分表下分页查询解决方案

    分库分表下分页查询解决方案 不管是随着业务量的增大.还是随着用户数量的增长,在单一表中无法承受大量大数据,导致查询速度极慢甚至拖垮数据库.所以分库分表的策略随之应用,但是如何在分库分表的情况下,进行分 ...

  2. .Net下的分库分表帮助类——用分库的思想来分表 - 秋夜 - 博客园

    .Net下的分库分表帮助类--用分库的思想来分表 - 秋夜 - 博客园

  3. 雪花算法——分库分表情况下id解决方案

    雪花算法--分库分表情况下id解决方案 分库分表的情况下id会遇到哪些挑战 分库分表id的解决方案 低并发情况下,使用中心数据库自增 使用不同步长数据库自增解决. 使用UUID 使用redis 使用M ...

  4. codeigniter3分表及列表查询处理

    文章目录 codeigniter3分表及列表查询处理 一个trait类文件 引入类文件 使用 必要函数放到helper文件中 codeigniter3分表及列表查询处理 一个trait类文件 该文件在 ...

  5. mysql 分表 条件查询,面试过关斩将:分库分表-sharding-jdbc分页,排序,条件查询优化...

    之前讲了利用sharding-jdbc 3.1进行分表的情况,也讲了利用一致性hash去做分表的高可用.今天讲下分表后的分页,排序,条件查询优化. 其实本身sharding-jdbc是提供了分页功能的 ...

  6. MySQL分库分表多维度查询——比较好的方法

    转载自:http://blog.itpub.net/29254281/viewspace-2086198/ MySQL分库分表,一般只能按照一个维度进行查询. 以订单表为例, 按照用户ID mod 6 ...

  7. mysql 自动 分库 备份_MySQL分库备份的方法

    分库备份的意义是什么 ? 有时一个企业的数据库里面有多个库,例如(www,bbs,cms),但是出问题时可能是某一个库,如果在备份时候把所有的库备份成一个数据文件的话,恢复数据就比较麻烦. 分库备份方 ...

  8. mysql 分表后查询_Mysql分表后怎么查询效率高?

    胸弟,mysql分表要慎之又慎,没有必要的情况下千万不要贸然分库分表.真到了非拆不可的时候,一定要结合实际业务,多花点时间做方案预研.像你们这个方案,按日期一天一张表,这完全是拍脑袋想出来的啊,给自己 ...

  9. ShardingSphere简单分库分表实现(根据int分库,根据时间分表)

    1.背景 公司最近的项目开发中有一个数据库表,在给甲方部署试运行阶段发现有一个接口查询速度特别慢,然后经过排查发现,这个数据库表的的数据每天以6000-9000条的量激增,两个多月的时间已经60多万条 ...

最新文章

  1. 机器学习与深度学习常见面试问题与答案
  2. docker容器 与 系统时间同步
  3. codeforces #222 div 1 D Developing Game
  4. boost::geometry::partition用法的测试程序
  5. 面向对象的软件工程应用浅研
  6. Redis 多机服务 : 主从同步、哨兵、集群
  7. 隐藏GridControl的“Drag a column header here to group by that column”
  8. mysql隔离级别验证_MySQL事务隔离级别以及验证
  9. python从excel中读取数据
  10. 使用Tomcat Maven插件进行项目部署
  11. ctf 绕过php,Bugku-CTF之各种绕过
  12. DWR第四篇之对象传参
  13. Spark streaming消费Kafka的正确姿势
  14. 训练集和测试集 — 模型评估
  15. 你真正了解图像金字塔吗?详细介绍拉普拉斯金字塔和高斯金字塔(pyrDown() and pyrUp()),参考《OpenCV轻松入门:面向Python》
  16. 【国仁网络资讯】视频号密集更新:唤醒的是谁的梦?
  17. AgentWeb , 一个简洁易用的 Android Web 库
  18. ES8388说明书CC1110F32RHHR 低功耗 1 GHz 无线芯片
  19. java 中 null==obj 与 obj==null
  20. 一键制作生日快乐的网站_生日快乐和一本新书

热门文章

  1. iOS之instancetype
  2. gui编程实践(2)--qq聊天界面 JTextArea多行文本框组件
  3. sublime3 常用功能总结
  4. 浏览器对象模型(BOM)
  5. 高精度加减乘法小程序
  6. 【读书笔记】设计模式沉思录
  7. 6个特征,判断你的领导值不值得追随
  8. python集合常用方法_Python中集合类型(set)学习小结
  9. 程序员千万不要做舔狗啊!
  10. 万字长文!不为人所知的分布式锁实现全都在这里了