NHibernate QueryOver 与 Fetch 产生多个 sql 查询和数据库命中

Posted

技术标签:

【中文标题】NHibernate QueryOver 与 Fetch 产生多个 sql 查询和数据库命中【英文标题】:NHibernate QueryOver with Fetch resulting multiple sql queries and db hits 【发布时间】:2013-10-17 12:46:11 【问题描述】:

我正在尝试选择一个实体并获取相关列表:

    Session.QueryOver<UserRole>()
           .Fetch(x => x.UsersInRole).Eager
           .List();

这会导致大量数据库命中。 第一个是这样的:

 SELECT ... FROM UserRoles
 left outer join UsersInRoles on ...

还有数百个单独的查询,看起来像:

 SELECT ... FROM UsersInRoles
 left outer join UserRoles on ...
 WHERE UserRoles.UserId=?

映射如下:

public class UserRoleMap : ClassMap<UserRole>

    public UserRoleMap()
    
        Id(x => x.Id);
        Map(x => x.RoleName);
        HasManyToMany(x => x.UsersInRole)
        .Inverse()
        .LazyLoad()
        .Table("UsersInRoles");
    

【问题讨论】:

【参考方案1】:

我想说,这种行为是我们应该预料到的。让我们有一个场景,其中我们在系统中有 2 个用户和 2 个角色

User1 - Role1 // has only Role1
User2 - Role1 // now we see that Role2 has more then User1
User2 - Role2

假设第一个查询将仅检索 User1 及其多对多关系 Role1。我们目前在ISession 中只有User1,因此Role1 的用户集不完整 (我们目前无法重用加载到 ISession 中的对象)。但是人们怎么知道我们在哪里呢?为Role1 加载的所有数据是否都在会话中?

必须发出新查询,加载Role1 的数据。通过这种方式,我们最终可以处理这些查询...

我认为最好的解决方案(我在几乎所有场景中都使用它)是batch-size 设置:19.1.5. Using batch fetching

HasManyToMany(x => x.UsersInRole)
  ...
  .BatchSize(25)

.BatchSize(25) 标记您的所有集合地图,甚至对类地图也这样做。这将导致超过 1 个 SQL 脚本,但最后 超过 1 + (2-4),具体取决于批处理大小和页面大小。

【讨论】:

尝试了您的建议。导致 1 + 12 个查询 - 比以前好多了,但没有办法让它少于 12 个吗? (增加批量大小?) - 批量大小的成本是多少?我猜如果一切都很好,它会默认设置。批量大小是唯一的解决方案吗?是否存在可能导致 2 个查询的连接?如果我需要自己用简单的 SQL 编写它,我认为 2 个查询就足够了。谢谢。 如果有比批量大小更好的解决方案,我不确定。默认情况下不启用此功能的原因可能是这样的事实,即这打破了简单的逻辑: uninitialize 对象的代理是一个驱动程序。它在需要时直接获取数据。批量调整会在会话上投入更多精力来加入这些 SELECTS。无论如何,批量大小在所有 我们的 集合和类映射上。即使在大型场景中,性能也令人惊叹

以上是关于NHibernate QueryOver 与 Fetch 产生多个 sql 查询和数据库命中的主要内容,如果未能解决你的问题,请参考以下文章

NHibernate Query<> 与 QueryOver<> 有啥区别?

NHibernate QueryOver 与 Fetch 产生多个 sql 查询和数据库命中

使用 NHibernate 3.0 QueryOver 或 LINQ 提供程序的权衡

如何使用 NHibernate QueryOver 重新创建这个复杂的 SQL 查询?

NHibernate 将 sql 查询转换为 NHibernate QueryOver 查询

如何在 Nhibernate 中对子集合进行 QueryOver