Performance NHibernate为多个父对象批量加载子对象
假设我们有一个类别表和产品表。以及每种产品的参考类别。因此,每个类别都有许多产品。 我想在没有产品的情况下加载许多类别(以减少数据库访问时间),然后检查我们实际需要的类别,并定义一个少得多的类别子集。 在此之后,我需要加载所选类别的所有产品,并使用单个DB查询将它们附加到类别。Performance NHibernate为多个父对象批量加载子对象,performance,nhibernate,fluent-nhibernate,bulk-load,Performance,Nhibernate,Fluent Nhibernate,Bulk Load,假设我们有一个类别表和产品表。以及每种产品的参考类别。因此,每个类别都有许多产品。 我想在没有产品的情况下加载许多类别(以减少数据库访问时间),然后检查我们实际需要的类别,并定义一个少得多的类别子集。 在此之后,我需要加载所选类别的所有产品,并使用单个DB查询将它们附加到类别。 我可以单独加载产品,但在这种情况下,它们不会附加到类别。这种方法,解决方案是在NHiberante中本地构建的。它被称为: NHibernate可以有效地利用批取,也就是说,如果访问一个代理(或集合),NHibernat
我可以单独加载产品,但在这种情况下,它们不会附加到类别。这种方法,解决方案是在NHiberante中本地构建的。它被称为: NHibernate可以有效地利用批取,也就是说,如果访问一个代理(或集合),NHibernate可以加载多个未初始化的代理。批取是对惰性选择获取策略的优化。有两种方法可以调整批取:在类和集合级别 类/实体的批处理抓取更容易理解。假设您在运行时遇到以下情况:ISession中加载了25个Cat实例,每个Cat都有一个对其所有者Person的引用。Person类映射了一个代理,lazy=“true”。如果您现在遍历所有cat并对每个cat调用cat.Owner,则默认情况下,NHibernate将执行25条SELECT语句以检索代理的所有者。您可以通过在Person:
。。。
NHibernate现在只执行三个查询,模式是10、10、5
您还可以启用集合的批量抓取。例如,如果每个人都有一个懒惰的Cats集合,并且ISession中当前加载了10个人,则遍历所有人将生成10个选择,每个对Person.Cats的调用一个选择。如果您在Person映射中启用Cats集合的批量抓取,则NHibernate c预取集合:
...
小结:有一个优化映射设置:batch size=“25”
我们可以在类级别上使用它(稍后用于多对一
关系)或在集合上使用它(直接在一对多
realtion上)
这将导致很少的SELECT语句来加载复杂的对象图。最重要的好处是,我们可以在查询根实体(无多行)时使用分页(Take()
,Skip()
)
检查,还有更多的链接…这可以通过HQL和futures实现 鉴于实体和地图如下所示
public class Category
{
private IList<Product> _products;
public Category()
{
_products = new List<Product>();
}
public virtual int Id { get; set; }
public virtual string CategoryName { get; set; }
public virtual IList<Product> Products
{
get { return _products; }
set { _products = value; }
}
}
public class CategoriesClassMap : ClassMap<Category>
{
public CategoriesClassMap()
{
Table("Categories");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.CategoryName);
HasMany<Product>(c => c.Products).LazyLoad();
}
}
public class Product
{
public virtual int Id { get; set; }
public virtual string ProductName { get; set; }
public virtual Category Category { get; set; }
}
public class ProductSClassMap : ClassMap<Product>
{
public ProductSClassMap()
{
Table("Products");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.ProductName);
References<Category>(x => x.Category).Not.Nullable();
}
}
相同(使用未来)适用于
查询版本
或标准
这里的问题是,我只需要加载选定类别的产品,而不需要加载所有已加载的产品。我真的不会尝试解决,也不会比本机内置功能更智能。只要尝试,用我的(嗯,NHibernate)加载所有类别的所有产品即可方法。检查性能。然后通过查询选择几个类别,然后再次加载所有产品。我相信,您会感到惊讶,几乎没有什么不同。使用内置功能很难替代刚选择的加载所带来的性能提升。我每天都在使用批处理大小,我确信我可以只查询一个根,如果需要,所有关系都会被加载。工作得非常好…这实际上是我们现在处理它的方式。但它仍然有一个问题-正在提取(并可能重建)选定的类别这是第二次。但这只需要执行2次SQL,1.加载所有类别以进行筛选2.为筛选类别获取所有类别+产品的查询。因此,即使您设法将已加载的产品附加到已加载的类别,这有什么区别?
<class name="Person">
<set name="Cats" batch-size="3">
...
</set>
</class>
public class Category
{
private IList<Product> _products;
public Category()
{
_products = new List<Product>();
}
public virtual int Id { get; set; }
public virtual string CategoryName { get; set; }
public virtual IList<Product> Products
{
get { return _products; }
set { _products = value; }
}
}
public class CategoriesClassMap : ClassMap<Category>
{
public CategoriesClassMap()
{
Table("Categories");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.CategoryName);
HasMany<Product>(c => c.Products).LazyLoad();
}
}
public class Product
{
public virtual int Id { get; set; }
public virtual string ProductName { get; set; }
public virtual Category Category { get; set; }
}
public class ProductSClassMap : ClassMap<Product>
{
public ProductSClassMap()
{
Table("Products");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.ProductName);
References<Category>(x => x.Category).Not.Nullable();
}
}
var categories = session.CreateQuery("from Category c join fetch c.Products where c.Id in (1,2)")
.Future<Category>().Distinct().ToList();
select category0_.Id as Id1_0_, products1_.Id as Id3_1_, category0_.CategoryName as Category2_1_0_, products1_.ProductName as ProductN2_3_1_, products1_.Category_id as Category3_3_1_, products1_.Category_id as Category3_0__, products1_.Id as Id0__ from Categories category0_ inner join Products products1_ on category0_.Id=products1_.Category_id where category0_.Id in (1 , 2);