【问题标题】:NHibernate SysCache2 and the Query Cache - Cannot avoid a Select N+1?NHibernate SysCache2 和查询缓存 - 无法避免 Select N+1?
【发布时间】:2013-01-07 09:48:53
【问题描述】:

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

流利:

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 所期望的那样。后续请求不会命中数据库,而使数据库中的记录失效会导致Entity失效,从而导致在下一次请求期间进行后续的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 他提到最后确保“实体也被缓存”

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

有什么想法吗?

【问题讨论】:

    标签: c# nhibernate syscache2


    【解决方案1】:

    根据您发布的两个链接,查询缓存会缓存查询产生的 ID,并开始一个一个地获取实体:如果您的缓存中有它们,那很好,如果没有,那么运气不好,您现在有很多选择。

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

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

    无论如何,我建议您查看 NHibernate 的 DEBUG 级别日志并查看二级缓存实际发生的情况,您将能够看到所有缓存命中/未命中。我可以给您的另一个提示是在您的配置中启用 generate_statistics 标志。流利:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-16
      • 1970-01-01
      • 1970-01-01
      • 2010-10-13
      • 1970-01-01
      相关资源
      最近更新 更多