NHibernate SysCache2和查询缓存 - 无法避免选择N + 1?

时间:2013-01-07 09:48:53

标签: c# nhibernate syscache2

我正在使用带有Fluent NHibernate的二级缓存提供程序SysCache2,使用标准的流畅配置(启用查询缓存似乎是一般建议),并且以通常的方式定义基于表的依赖项。

流利:

config.Cache(c => c
 .ProviderClass<NHibernate.Caches.SysCache2.SysCacheProvider>()
 .UseQueryCache()
 .UseSecondLevelCache()
 .UseMinimalPuts()

Web.Config中:

  <cacheRegion name="User" relativeExpiration="7200">
<dependencies>
  <tables>
    <add name="User" databaseEntryName="OldClient" tableName="tbl_users" />
  </tables>
</dependencies>

用户映射:

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Table("Users");
        ....
        // caching
        Cache.IncludeAll().ReadWrite().Region("Users");
    }
}

对于单个请求,所有内容都按预期运行,即:

Session<User>.Get()
正如NHibernate caches by ID所期望的那样。后续请求未命中数据库,并且使数据库中的记录无效会导致实体无效,从而导致在下一个请求期间进行后续SQL调用。一切都好。

问题在于查询缓存。首先,一切正常。执行如下调用:

Session<User>.Query(item => item.Active == true) 

导致SQL调用正如您所期望的那样(SELECT * FROM Users WHERE Active = true)。后续执行导致没有SQL。大。直到在数据库中更改来自查询集的单个记录的时间。执行相同的查询然后导致SELECT N + 1:

SELECT * FROM Users WHERE ID = 1
SELECT * FROM Users WHERE ID = 2
SELECT * FROM Users WHERE ID = 3
SELECT * FROM Users WHERE ID = 4
...

我在其他地方找到了对此的引用,但没有解决方案:

StackOverflow - How do I make NHibernate cache fetched child collections?请参阅“另外一点”部分

Ayende Caching Strategies他提到确保'实体也在最后被缓存'

目前我唯一能避免这种情况的方法是在每次请求后清除查询缓存 - 这几乎使它无用。我需要查询缓存来清除特定实体在该实体失效时的所有内容 - 而不仅仅是单个记录。

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

根据您发布的两个链接,查询缓存会缓存查询产生的ID并逐个启动实体:如果您在缓存中有这些实体,那么好,如果没有,运气不好,您现在有很多选择。

此时我假设您选择的实体不在二级缓存中(不再?)。我从未使用过基于表的依赖项,我们正在使用command based dependencies,我刚刚测试过如果一个实体被标记为无效,只有这个缓存的实体而不是整个缓存区域被抛出缓存。

检查配置以确保它是正确的,也许当您认为您正在使用二级缓存时,您实际上正在访问会话缓存?确保您正在测试缓存是否正在不同的会话。

在任何情况下,我建议你查看NHibernate的DEBUG级别日志,看看二级缓存实际发生了什么,在那里你将能够看到所有缓存命中/未命中。我可以给你的另一个技巧是在你的配置中启用generate_statistics标志。流利:

config.ExposeConfiguration(c => c.SetProperty("generate_statistics", "true"));

在此之后,您可以访问会话工厂中的有趣数据,例如Session.SessionFactory.Statistics.SecondLevelCacheMissCountSession.SessionFactory.Statistics.SecondLevelCacheHitCount。通过这两种方法的结合,您应该能够找出问题的原因。