当前位置:首页 » 文件管理 » 2000条数据分页缓存

2000条数据分页缓存

发布时间: 2023-08-08 07:55:36

⑴ 如何将分页数据 放入redis

普通分页
一般分页做缓存都是直接查找出来,按页放到缓存里,但是这种缓存方式有很多缺点。
如缓存不能及时更新,一旦数据有变化,所有的之前的分页缓存都失效了。
比如像微博这样的场景,微博下面现在有一个顶次数的排序。这个用传统的分页方式很难应对。
一种思路
最近想到了另一种思路。
数据以ID为key缓存到Redis里;
把数据ID和排序打分存到Redis的skip list,即zset里;
当查找数据时,先从Redis里的skip list取出对应的分页数据,得到ID列表。
用multi get从redis上一次性把ID列表里的所有数据都取出来。如果有缺少某些ID的数据,再从数据库里查找,再一块返回给用户,并把查出来的数据按ID缓存到Redis里。
在最后一步,可以有一些小技巧:
比如在缺少一些ID数据的情况下,先直接返回给用户,然后前端再用ajax请求缺少的ID的数据,再动态刷新。

还有一些可能用Lua脚本合并操作的优化,不过考虑到Lua脚本比较慢,可能要仔细测试。
如果是利用Lua脚本的话,可以在一个请求里完成下面的操作:
查找某页的所有文章,返回已缓存的文章的ID及内容,还有不在缓存里的文章的ID列表。
其它的一些东东:
Lua是支持LRU模式的,即像Memcached一样工作。但是貌似没有见到有人这样用,很是奇怪。
可能是用redis早就准备好把redis做存储了,也不担心内存的容量问题。

⑵ redis 怎么缓存用户列表,做到可以分页展示

redis是类似key_value形式的快速缓存服务。类型较丰富,可以保存对象、列表等,支持的操作也很丰富,属于内存数据库,且可以把内存中的数据及时或定时的写入到磁盘。可设置过期自动删除,速度快,易于使用。

⑶ 缓存分页合适吗

一种是使用本地缓存、另一种是分级缓存。这里谈一谈原设计的缺陷,分级缓存中我提出来通过确定两个不同size的缓存块来缓存两种级别的数据,这里带来一些问题:size的大小难以确定、为了避免边界问题大缓存数据包含了小缓存数据这就带来了缓存数据的冗余(这背离了我们设计的初衷)。针对这些问题我们又在原有基础上结合了应用场景的特殊性修改分级缓存为分页缓存(因为对数据列表的访问往往都是伴随分页需求的),将数据库中原始数据中较常使用部分按照固定大小的页进行缓存,服务端根据客户端分页的数据请求到相应的缓存页内查找数据进行填充。采用分页缓存一方面解决了缓存数据冗余的问题,也不用关注分级的边界,虽然相比分级缓存,分页的内容要零散一些,但是总体上而言灵活性要更高。这里谈谈为什么采用固定大小页进行缓存而不是按照客户端分页请求来缓存结果?如果服务端根据客户端分页请求进行缓存这种耦合关系会导致缓存命中率的下、降性能降低,特别是多类型客户端就更糟糕了。按照固定大小页进行缓存类似与MVC模式中将处理逻辑与显示逻辑解耦的思想,服务端的缓存不要依赖客户端,一方面提高了缓存命中率同时也为缓存清理提供了遍历。 下面是我使用IL动态生成的一个Demo反编译后的代码(这里针对了同时启用本地缓存和分页缓存的情况,还支持分页缓存无本地缓存、仅进行memcache缓存,这里就不加赘述了),可读性不高不想看直接pass吧。 C#代码 public override ListObject GetList(int num5, int num6, int num1, int num4) { ListObject local; int num = num1; int num2 = num4; int num3 = ((num1 - 1) * num4) % 100; num1 = (((num1 - 1) * num4) / 100) + 1;//计算缓存页对应的页码和页大小 num4 = 100; if (num1 > 10)//不在缓存页内直接进行数据库查询 { return base.GetList(num5, num6, num, num2); } ListObject obj3 = new ListObject(); do { string str = string.Concat(new object[] { "DemoCachekeyName", "|", num5, "|", num6, "|", num1, "|", num4 });//根据客户端分页请求计算出对应的cachekey local = CacheManager.get_Instance().GetLocal(str) as ListObject;//LocalCache的访问 if (local == null) { DateTime time; local = CacheManager.get_Instance().Get(str) as ListObject;//访问memcache if (local == null) { local = base.GetList(num5, num6, num1, num4); if (local != null) { time = DateTime.Now.AddSeconds(3600.0); CacheManager.get_Instance().Set(str, local, time); } } if (local != null) { time = DateTime.Now.AddSeconds(100.0); CacheManager.get_Instance().SetLocal(str, local, time); } } num1++; } while (((num1 (obj3, num2, num3, local));//填充结果集 if (obj3.totalCount == 0) { return null; } return obj3; } public override ListObject GetList(int num5, int num6, int num1, int num4){ ListObject local; int num = num1; int num2 = num4; int num3 = ((num1 - 1) * num4) % 100; num1 = (((num1 - 1) * num4) / 100) + 1;//计算缓存页对应的页码和页大小 num4 = 100; if (num1 > 10)//不在缓存页内直接进行数据库查询 { return base.GetList(num5, num6, num, num2); } ListObject obj3 = new ListObject(); do { string str = string.Concat(new object[] { "DemoCachekeyName", "|", num5, "|", num6, "|", num1, "|", num4 });//根据客户端分页请求计算出对应的cachekey local = CacheManager.get_Instance().GetLocal(str) as ListObject;//LocalCache的访问 if (local == null) { DateTime time; local = CacheManager.get_Instance().Get(str) as ListObject;//访问memcache if (local == null) { local = base.GetList(num5, num6, num1, num4); if (local != null) { time = DateTime.Now.AddSeconds(3600.0); CacheManager.get_Instance().Set(str, local, time); } } if (local != null) { time = DateTime.Now.AddSeconds(100.0); CacheManager.get_Instance().SetLocal(str, local, time); } } num1++; } while (((num1 (obj3, num2, num3, local));//填充结果集 if (obj3.totalCount == 0) { return null; } return obj3;}(下次再完善这里的IL代码的流程图,一直想在缓存结果中再织入进一些过滤操作思前想后没想到如何在不污染原有接口的前提下实现,正在努力中...) PS:关于IL代码编写:IL代码因为是一种中间代码可读性不是很高,所以进行IL编码其实还是有一点难度的(学习IL编码可以参看《IL Emit学习之旅》一问)。我简单谈谈我在编写IL代码中遇到的一些小问题和自己总结的一些技巧。 1.先编写c#代码的demo,再参照其IL指令,先完成代码框架,在进一步编码。在IL编码前可以先写一个目标生成的动态代码,再通过参照其IL代码进编码,先用IL写出的主体逻辑(即if else、for、while等),再进一步完善。这样逐步编码查错和编码效率都相对高一点。 2.什么时候用“_S”,IL代码中为了缩减指令长度对于某些同一操作提供了两种指令实现,比如无条件跳转有Br、Br_S,有时候使用Br_S跳转目标地址会被截断导致程序出错。我个人觉得可以先在可能出现这类情况的地方使用不带“_S”的指令,待动态代码生成后查看其IL代码,再对指令进行优化。 关于泛型函数的反射: IL代码中常常需要调用函数,这就需要使用到反射(第一次生成动态代码时的反射对整体的性能影响还是可以接受的)。泛型函数的反射还是稍稍有些绕的: C#代码 //目标函数public static bool FillResult(...) MethodInfo fillResult= typeof(PageFormatUtil).GetMethod("FillResult"); fillResult=fillResult.MakeGenericMethod(info.ReturnParameter.ParameterType.GetGenericArguments()[0]);//info.ReturnParameter.ParameterType.GetGenericArguments()获取函数返回结果中泛型参数的信息,MakeGenericMethod之后才是真正完成了泛型函数的反射 //目标函数public static bool FillResult(...)MethodInfo fillResult= typeof(PageFormatUtil).GetMethod("FillResult");fillResult=fillResult.MakeGenericMethod(info.ReturnParameter.ParameterType.GetGenericArguments()[0]);//info.ReturnParameter.ParameterType.GetGenericArguments()获取函数返回结果中泛型参数的信息,MakeGenericMethod之后才是真正完成了泛型函数的反射C#代码 //public class ListObject{...} reflectType=typeof(ListObject).MakeGenericType(info.ReturnParameter.ParameterType.GetGenericArguments()[0]); reflectConstruct=reflectType.GetConstructor(new Type[]{}); //public class ListObject{...}reflectType=typeof(ListObject).MakeGenericType(info.ReturnParameter.ParameterType.GetGenericArguments()[0]);reflectConstruct=reflectType.GetConstructor(new Type[]{});缓存分页合适吗

热点内容
滑板鞋脚本视频 发布:2025-02-02 09:48:54 浏览:432
群晖怎么玩安卓模拟器 发布:2025-02-02 09:45:23 浏览:557
三星安卓12彩蛋怎么玩 发布:2025-02-02 09:44:39 浏览:743
电脑显示连接服务器错误 发布:2025-02-02 09:24:10 浏览:537
瑞芯微开发板编译 发布:2025-02-02 09:22:54 浏览:146
linux虚拟机用gcc编译时显示错误 发布:2025-02-02 09:14:01 浏览:232
java驼峰 发布:2025-02-02 09:13:26 浏览:651
魔兽脚本怎么用 发布:2025-02-02 09:10:28 浏览:532
linuxadobe 发布:2025-02-02 09:09:43 浏览:212
sql2000数据库连接 发布:2025-02-02 09:09:43 浏览:726