c# - NHibernate SysCache2 和查询缓存 - 无法避免 Select N+1?

标签 c# nhibernate syscache2

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

流利:

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

)

网络配置:

  <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他最后提到确保“实体也被缓存”

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

有什么想法吗?

最佳答案

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

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

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

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

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

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

关于c# - NHibernate SysCache2 和查询缓存 - 无法避免 Select N+1?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14193392/

相关文章:

c# - Entity Framework 代码首先未将对象引用设置为对象的实例

c# - 如何在 conversionType 为十进制且输入为 "40.00"时使用 Convert.ChangeType()

c# - 我如何按字符串属性而不是按字母顺序排序

c# - 有条件的分组、求和、相减

c# - Linq 缓慢具体化复杂查询

nhibernate - nhibernate 是否在 TransactionScope 中创建隐式事务?

.net - 如何使 NHibernate 缓存获取的子集合?

c# - QueryOver: 选择 ... where property in (...)

nhibernate - Fluent NHibernate Syscache2 缓存过期

nhibernate L2缓存: configure by code