在.NET webapp中缓存复杂搜索查询的最佳方法是什么?

时间:2012-01-26 16:39:22

标签: asp.net .net performance caching

我有一个网站,允许用户使用各种搜索条件查询特定食谱。例如,您可以说“向我展示我可以在30分钟内使用鸡肉,大蒜和面食而不是橄榄油制作的所有食谱。”

此查询通过JSON发送到Web服务器,并反序列化为SearchQuery对象(具有各种属性,数组等)。

实际的数据库查询本身相当昂贵,并且有很多默认搜索模板会经常使用。出于这个原因,我想开始缓存常见的查询。我已经对各种缓存技术进行了一些调查,并阅读了很多关于这个主题的其他SO帖子,但我仍然在寻找建议。现在,我正在考虑以下选项:

  1. 内置System.Web.Caching这可以很好地控制缓存中的项目数,过期时间及优先级。但是,缓存的对象由字符串键入,而不是可哈希的对象。我不仅需要能够将SearchQuery对象转换为字符串,而且哈希必须是完美的并且不会产生任何冲突。
  2. 开发我自己的InMemory缓存:我真正喜欢的是一个Dictionary<SearchQuery, Results>对象,它在所有会话中都存在于内存中。由于搜索结果可能会变得相当大,我希望能够限制缓存多少查询并为旧查询提供过期方式。像FIFO队列这样的东西在这里可以很好地工作。我担心线程安全等问题,我想知道编写自己的缓存是否值得付出努力。
  3. 我还研究过其他一些第三方缓存提供商,例如NCacheVelocity。这些都是分布式缓存提供商,对我目前所需要的东西来说可能完全过度。此外,似乎我看到的每个缓存系统仍然需要通过字符串键入对象。理想情况下,我想要一个包含缓存的东西,允许我按对象的哈希值键入,并允许我控制到期时间和优先级。

    我很感激任何建议或参考免费和优选的开源解决方案,可以帮助我在这里。谢谢!

4 个答案:

答案 0 :(得分:4)

根据您的说法,我建议您使用System.Web.Caching并将其构建到您的DataAccess图层中,以便将其与其他人保护。调用时,您可以根据业务/应用程序需求进行实时查询或从缓存对象中提取。我今天这样做,但是Memcached

答案 1 :(得分:2)

快速查看Enterprise library缓存应用程序块。假设您需要一个Web应用程序范围的缓存,这可能是您正在寻找的解决方案。

答案 2 :(得分:2)

内存缓存应该很容易实现。我无法想到为什么你应该特别关注验证SearchQuery对象与任何其他对象的唯一性的任何原因 - 也就是说,当键必须是一个字符串时,你可以只存储原始对象缓存中的结果,并在您对哈希进行命中后直接验证相等性。我会使用System.Web.Caching来表示您注意到的好处(到期等)。如果碰巧碰撞,那么第二个就不会被缓存。但这种情况极为罕见。

此外,存储搜索结果所需的内存量应该是微不足道的。您不需要完整详细地保留每一行的每个字段的数据。您只需要快速访问每个结果,例如一个int主键。

最后,如果可能有数千个搜索结果可以缓存,您甚至不需要为每个搜索结果保留一个ID - 只需保留前100个或其他内容(以及总点击次数) )。我怀疑如果你分析人们如何使用搜索结果,那么这是一个超出几页的罕见人物。如果有人这样做,那么你可以再次运行查询。

所以基本上你只是存储每个常见搜索的前X条记录的主键,然后如果你的缓存命中,你所要做的就是运行一个非常便宜的少数索引查找密钥。

答案 3 :(得分:1)

我假设从SearchQuery对象生成数据库查询并不昂贵,并且您希望缓存从执行查询中获得的结果(即行集)。

您可以从SearchQuery对象生成查询文本,并使用该文本作为使用System.Web.Caching进行查找的键。

从快速阅读Cache类的文档看来,密钥必须是唯一的 - 如果您使用它们查询文本,它们就是它们 - 而不是密钥的哈希值。

修改

如果您担心长缓存密钥,请检查以下链接:

Cache key length in asp.net

Maximum length of cache keys in HttpRuntime.Cache object?

似乎Cache类将缓存的项存储在内部字典中,该字典使用密钥的哈希。具有相同散列的密钥(查询文本)最终将在字典中的同一个存储桶中进行,其中只需快速线性搜索以在执行高速缓存查找时找到所需的存储区。所以我认为你可以使用长键串。

asp.net缓存是经过深思熟虑的,我不认为这是你需要其他东西的情况。