热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

redis和mysql数据做混合分页查询_分页查询和redis

当查询结果包含的数据量非常大的时候,往往需要分页查询。本文总结一些分页查询的技巧,及如何用mysqlcassandra和redis等实现分页查询的方案。

当查询结果包含的数据量非常大的时候,往往需要分页查询。本文总结一些分页查询的技巧,及如何用mysql cassandra和redis等实现分页查询的方案。

问题

我在做论坛的是时候遇到了如下的问题。论坛里可以有很多的主题topic,每个topic对应到很多回复reply。现在要查询某个topic下按照replyTime升序排列的第pageNo页的reply,每页pageSize个reply。 reply是存放在mysql中的。以前的实现是利用mysql的limit查询

select * from reply where topicId = ? order by replyTime asc limit (pageNo - 1) * pageSize, pageSize

由于现在有很多的主题的回复很多,当有人查询第几百甚至几千页的时候,mysql性能表现很不好。“select limit offset, size” 只要offset太大,传统的关系型数据库的性能表现都不好。 如果能够利用带索引的查询条件先过滤掉一部分数据,就可以大大提高性能,比如:

select

*

from

reply

where

topicId = ?

and replyId > lastReplyIdOfCurrentPage

order by

replyTime asc

limit

(pageNo - currentPageNo) * pageSize, pageSize

lastReplyIdOfCurrentPage 是当前页的最后一个reply的id。currentPageNo是当前页的页号。这里用replyId过滤条件,把前面页的内容过滤掉,这样减少了offset的大小。但是当用户需要跳转到很远的一个页面的时候,offset还是会很大。比如,当前是第10页,要跳转到第1000页,offset = 990 * pageSize,还是会很大,性能依旧不行。尽管目前很多产品,都不提供这样的跳转能力了,但是我们的产品团队还是认为这个功能在我们的产品里面不可或缺。

迁移到cassandra

后来我们把reply数据全部迁移到了cassandra上。cassandra的数据结构和mysql不一样。我们创建了一个topic_reply 列簇,每一行的行号是topicId,每一列是这个topic的replyId,这样得到类似如下结构 1:1,2,5,33,245,663,780... 2:36,78,89,94,235,345... 在cassandra中列是自然排序的,形成了一个从topic到reply的索引。查询的时候只能查询topicId行的列大于(或小于)replyId的size个replyId,相当于sql: select * from topic_reply where replyId > ? limit size, 不能够 "limit offset, size"。这意味着如果要查询第一千页,而我不知道第一千页开始的replyId是多少,我就得取出这一千页的数据,这显然是行不通的。所以得想办法从靠近我要取的数据的某个replyId处开始取数据。

reids的SortedSet

无论是mysql还是cassandra,都不能很好地解决从一个很长的序列中取出任意一段数据的问题,而造成这一问题的根源在于这些数据是存放在磁盘上的,磁盘不适合做此类的随机读的操作。所以想,如果能有一个程序,管理一些很大很大的放在内存中排序数组就好了,因为对内存中的数组做下标访问,是非常快速的。做了一下调查正好发现,redis提供了此类的功能。 redis将数据存放到内存中,所以既便是随机读写,速度都是非常快。redis支持的SortedSet结构正好适合于做分页查询。SortedSet按照给定的score给member排序,允许通过下标或者score去查询。把同一个topic的replyId作为member,以replyId本身为score存放到SortedSet后,就可以通过下标取值了,例如:

//存入数据

zadd tr:1 1 1

zadd tr:1 2 2

zadd tr:1 5 5

zadd tr:1 33 33

zadd tr:1 245 245

zadd tr:1 663 663

//pageSize = 3 取 第二页,即下标 3 到5的元素

zrange tr:1 3 5

其中 tr:1 是这个SortedSet的key,"tr:"只是用来区分其它key用的前缀,1是topicId。更详细的内容看redis官网 http://redis.io 如此一来,就可以实现任意分页查询了,而且性能非常好。

缓存索引

redis的数据全部存放到内存中,如果把所有topic到reply的关系都放到内存中,要耗费很多内存,而且这么多的内存实际上很多是浪费的,毕竟大部分的topic是不活跃的。再者topic到reply的映射关系是非常重要的,所以我们需要把这种关系持久化。最后我们决定,这个映射关系,或者称为索引还是存放在cassandra里面,只是在需要的时候,才从cassandra里面把索引载入到redis内,然后再利用redis分页查询。如此一来,redis成了一个支持分页查询的强大的缓存。

分片缓存

对于超长的主题,全新载入到redis一次也是相当的耗时的,我们采取分片来解决这个问题。我们把索引每4800个值分成一片,用另外一个数据结构记录索引长度和索引从第二片开始的每片的开始值。

54f5ff24eb52f1ba8d7d054e13002bc0.png更新的索引的时候更新这个分片信息,记录各分片的头部是为了便于从cassandra载入分片。 查询的时候把分页查询转化成某个片上某段索引的值。当分片大小大于pageSize并且能被pageSize整除时,这个转化是很简单的,因为分页正好会全部落在某一个分片中。我们之所以把分片大小设置成4800正是因为这个值能被10 15 20 25 30 40 50 60 80 100 200 等很多常用分页大小整除。分片太大浪费内存,分片太小分片就太多。 只要算出这一页所在的分片,然后把需要的索引段载入到redis,再利用redis的分页查询查出结果。这样,只有活跃的索引分段才会被载入到redis内存中。 如果用mysql来持久化索引效果也是类似的,而且查询更加便利能力更强。

总结

只要产品能接受,就不要使用任意分页,任意跳转。确实需要高速分页查询的时候可以使用redis的SortedSet,但是得注意内存大小和持久化问题。



推荐阅读
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • Monkey《大话移动——Android与iOS应用测试指南》的预购信息发布啦!
    Monkey《大话移动——Android与iOS应用测试指南》的预购信息已经发布,可以在京东和当当网进行预购。感谢几位大牛给出的书评,并呼吁大家的支持。明天京东的链接也将发布。 ... [详细]
  • 本文介绍了[从头学数学]中第101节关于比例的相关问题的研究和修炼过程。主要内容包括[机器小伟]和[工程师阿伟]一起研究比例的相关问题,并给出了一个求比例的函数scale的实现。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了游标的使用方法,并以一个水果供应商数据库为例进行了说明。首先创建了一个名为fruits的表,包含了水果的id、供应商id、名称和价格等字段。然后使用游标查询了水果的名称和价格,并将结果输出。最后对游标进行了关闭操作。通过本文可以了解到游标在数据库操作中的应用。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了三种方法来实现在Win7系统中显示桌面的快捷方式,包括使用任务栏快速启动栏、运行命令和自己创建快捷方式的方法。具体操作步骤详细说明,并提供了保存图标的路径,方便以后使用。 ... [详细]
author-avatar
灬丶领袖
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有