2011-11-18 29 views
3

说我有这些查询如何在nhibernate中使用ToFuture?

// Linq 
    var allRecords = session.Query<Table1P>().FetchMany(x => x.Table2).FetchMany(x => x.Table3).FetchMany(x => x.Table4).FetchMany(x => x.Table6).ToList(); 

// Hql 
string hqlQuery = @"from Table1 tbl1 
           left join fetch tbl1.Table2 tbl2 
           left join fetch tbl1.Table3 
           left join fetch tbl1.Table4 
           left join fetch tbl1.Table6 
           left join fetch tbl2.Table5s"; 

在上述情况下,我需要做的所有这些连接停止延迟加载,并做预先加载。现在这会在nhibernate分析器中产生一个关于太多连接的警报。

http://nhprof.com/Learn/Alerts/TooManyJoins

所以一个方法来阻止这种警告是分手的连接。并做多个查询。这是我想要做的。然而,与此同时,我一直在阅读关于未来的特性,我认为这将允许我分解查询(阻止太多连接),但仍然一次执行它。

编辑

我一直在努力ToFuture并试图限制数据量要回来的时候发现它比较慢(如果我试图让一切恢复那么快,因为它不会崩溃) 。

var allRecords = session.Query<Table1P>().FetchMany(x => x.Table2).FetchMany(x => x.Table3).FetchMany(x => x.Table4).FetchMany(x => x.Table6).Take(3000).ToList(); 

// result (2.731 seconds), row count 3000, duration 8 ms/ 2013 ms 

select TOP (3000 /* @p0 */) table1p0_.Id  as Id1_0_, 
       table2x1_.Id  as Id2_1_, 
       table3x2_.Id  as Id3_2_, 
       table4x3_.Id  as Id4_3_, 
       table6x4_.Id  as Id6_4_, 
       table1p0_.F1  as F2_1_0_, 
       table1p0_.F2  as F3_1_0_, 
       table1p0_.F3  as F4_1_0_, 
       table2x1_.F1  as F2_2_1_, 
       table2x1_.F2  as F3_2_1_, 
       table2x1_.F3  as F4_2_1_, 
       table2x1_.Table1_id as Table5_2_1_, 
       table2x1_.Table1_id as Table5_0__, 
       table2x1_.Id  as Id0__, 
       table3x2_.F1  as F2_3_2_, 
       table3x2_.F2  as F3_3_2_, 
       table3x2_.F3  as F4_3_2_, 
       table3x2_.Table1_id as Table5_3_2_, 
       table3x2_.Table1_id as Table5_1__, 
       table3x2_.Id  as Id1__, 
       table4x3_.F1  as F2_4_3_, 
       table4x3_.F2  as F3_4_3_, 
       table4x3_.F3  as F4_4_3_, 
       table4x3_.Table1_id as Table5_4_3_, 
       table4x3_.Table1_id as Table5_2__, 
       table4x3_.Id  as Id2__, 
       table6x4_.F1  as F2_6_4_, 
       table6x4_.F2  as F3_6_4_, 
       table6x4_.F3  as F4_6_4_, 
       table6x4_.Table1_id as Table5_6_4_, 
       table6x4_.Table1_id as Table5_3__, 
       table6x4_.Id  as Id3__ 
from Table1 table1p0_ 
     left outer join [Table2] table2x1_ 
     on table1p0_.Id = table2x1_.Table1_id 
     left outer join [Table3] table3x2_ 
     on table1p0_.Id = table3x2_.Table1_id 
     left outer join [Table4] table4x3_ 
     on table1p0_.Id = table4x3_.Table1_id 
     left outer join [Table6] table6x4_ 
     on table1p0_.Id = table6x4_.Table1_id 

使用ToFuture

// result (4.808 seconds), row count 6944/75/ 374, duration 1ms/4022 ms 

       // will load the Entities with Table2 fetched 
       var allRecords = session.Query<Table1P>() 
        .FetchMany(x => x.Table2) 
        .ToFuture() 
        .Take(3000); 

       // will load the Entities with Table3 fetched 
       session.Query<Table1P>() 
        .FetchMany(x => x.Table3) 
        .ToFuture(); 

       // will load the Entities with Table4 fetched 
       session.Query<Table1P>() 
        .FetchMany(x => x.Table4) 
        .ToFuture(); 

       // will load the Entities with Table6 fetched 
       session.Query<Table1P>() 
        .FetchMany(x => x.Table6) 
        .ToFuture(); 

       // will trigger all queries at once and the session cache will make sure, 
       // that the results of all queries fill the same Entities 
       allRecords.ToList(); 


select table1p0_.Id  as Id1_0_, 
     table2x1_.Id  as Id2_1_, 
     table1p0_.F1  as F2_1_0_, 
     table1p0_.F2  as F3_1_0_, 
     table1p0_.F3  as F4_1_0_, 
     table2x1_.F1  as F2_2_1_, 
     table2x1_.F2  as F3_2_1_, 
     table2x1_.F3  as F4_2_1_, 
     table2x1_.Table1_id as Table5_2_1_, 
     table2x1_.Table1_id as Table5_0__, 
     table2x1_.Id  as Id0__ 
from Table1 table1p0_ 
     left outer join [Table2] table2x1_ 
     on table1p0_.Id = table2x1_.Table1_id; 



select table1p0_.Id  as Id1_0_, 
     table3x1_.Id  as Id3_1_, 
     table1p0_.F1  as F2_1_0_, 
     table1p0_.F2  as F3_1_0_, 
     table1p0_.F3  as F4_1_0_, 
     table3x1_.F1  as F2_3_1_, 
     table3x1_.F2  as F3_3_1_, 
     table3x1_.F3  as F4_3_1_, 
     table3x1_.Table1_id as Table5_3_1_, 
     table3x1_.Table1_id as Table5_0__, 
     table3x1_.Id  as Id0__ 
from Table1 table1p0_ 
     left outer join [Table3] table3x1_ 
     on table1p0_.Id = table3x1_.Table1_id; 



select table1p0_.Id  as Id1_0_, 
     table4x1_.Id  as Id4_1_, 
     table1p0_.F1  as F2_1_0_, 
     table1p0_.F2  as F3_1_0_, 
     table1p0_.F3  as F4_1_0_, 
     table4x1_.F1  as F2_4_1_, 
     table4x1_.F2  as F3_4_1_, 
     table4x1_.F3  as F4_4_1_, 
     table4x1_.Table1_id as Table5_4_1_, 
     table4x1_.Table1_id as Table5_0__, 
     table4x1_.Id  as Id0__ 
from Table1 table1p0_ 
     left outer join [Table4] table4x1_ 
     on table1p0_.Id = table4x1_.Table1_id; 



select table1p0_.Id  as Id1_0_, 
     table6x1_.Id  as Id6_1_, 
     table1p0_.F1  as F2_1_0_, 
     table1p0_.F2  as F3_1_0_, 
     table1p0_.F3  as F4_1_0_, 
     table6x1_.F1  as F2_6_1_, 
     table6x1_.F2  as F3_6_1_, 
     table6x1_.F3  as F4_6_1_, 
     table6x1_.Table1_id as Table5_6_1_, 
     table6x1_.Table1_id as Table5_0__, 
     table6x1_.Id  as Id0__ 
from Table1 table1p0_ 
     left outer join [Table6] table6x1_ 
     on table1p0_.Id = table6x1_.Table1_id; 

查询和时间从NHibernate的探查取。测试是通过运行一组代码,记录结果,停止.net开发服务器,然后运行另一组代码来运行的。

表1 - 6200行 表2 - 744行 表3 - 75行 表4 - 374行 表6 - 300行

差不多表1具有一对多的所有其他表。

+0

你的'.Take(3000)'应该放在'.ToFuture()'之前,如果你想将它作为'TOP(3000)' –

+0

啊应用到查询中。好吧现在我得到了3021/3998/374/300的行数。持续时间35ms/4825共5.703秒。在一举之中,我可以获得3000行,持续时间为2ms/2307毫秒,总共为3.33。似乎ToFuture()需要返回更多的行才能获得相同的数量并且速度较慢。不知道这是如何,或者如果我仍然做错了什么。 – chobo2

回答

2
// will load the Entities with Table2 fetched 
var allRecords = session.Query<Table1P>() 
    .FetchMany(x => x.Table2) 
    .ToFuture(); 

// will load the Entities with Table3 fetched 
session.Query<Table1P>() 
    .FetchMany(x => x.Table3) 
    .ToFuture(); 

// will load the Entities with Table4 fetched 
session.Query<Table1P>() 
    .FetchMany(x => x.Table4) 
    .ToFuture(); 

// will load the Entities with Table6 fetched 
session.Query<Table1P>() 
    .FetchMany(x => x.Table6) 
    .ToFuture(); 

// will trigger all queries at once and the session cache will make sure, 
// that the results of all queries fill the same Entities 
allRecords.ToList(); 

变化

 .ToFuture() 
     .Take(3000); 

 .Take(3000); 
     .ToFuture() 

更新:

// Hql 
var allRecords = session.CreateQuery("from Table1 left join fetch tbl1.Table2") 
    .ToFuture<Table1>(); 

... 

奇怪的是,这是比大加入慢。我现在无法在这里测试。也许在db中没有那么多的行,多个结果集的开销大于extensiv连接的开销。你可以尝试使用db中的更多数据吗?

+0

我想,我尝试了一些非常相似的东西(我会再试一次)。但是我注意到它实际上比较慢,只是一气呵成。我还发现它返回的行数多于所有的数量(这也是为什么它可能会变慢)。这是预期的吗? – chobo2

+0

嗯,也许它不会变慢。我将不得不尝试与未来进行比较(如果我试图在不采取任何措施的情况下完成所有工作,则会发生内存不足异常)。我该怎么做这件事?所有的查询?第一个?假设我想要从Table1P中返回3000行,我只是做了一些,剩下的只会从表1中拿回那些?另外你如何做这个查询在HQL? – chobo2

+0

请参阅编辑结果。 – chobo2