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 查询?