2012-06-06 20 views
0

我有一個在NHibernate 3.0中使用Linq到NHibernate的asp.net web應用程序。OutOfMemory異常,而在LINQ中使用QueryOver <>獲取大型數據到Nhibernate

在一個函數中,我需要從一個表中獲得20000條記錄,其中包含1000萬條20列的記錄。

我正在使用Session.QueryOver <>()方法獲取記錄。

功能代碼:

public IList<BatchDetails> GetBatchRecordsOnBatchId_BatchSize(int batchId,int stratingRowdId,int batchSize) 
    { 
     // If the stratingRowdId will be 0 than frist count of the Batch Records equivlent to the batchSize will be return 

     //If the batchSize will be 0 than all the Batch Records starting from the RowId equivlent to the stratingRowdId will be return 

     // If both the stratingRowdId & batchSize are 0 than all the BatchReocrds for the BatchId will be return 



     if (batchId <= 0) 
     { 

      throw new ArgumentException(); 
     } 
     using (var session = _sessionFactory.OpenSession()) 
     { 
      using (var transaction = session.BeginTransaction()) 
      { 
       try 
       { 
        //Get Batch data from the Database for the BatchId 
        var batchData = from batchRecords in session.QueryOver<BatchDetails>() 
             .Where(x => x.BatchId == batchId) 
             .List().Skip(stratingRowdId).Take(batchSize) 
            select batchRecords 
         ; 

        transaction.Commit(); 
        return batchData.ToList(); 
       } 
       catch (ArgumentException ex) 
       { 
        if (transaction != null) transaction.Rollback(); 


        throw; 
       } 
       catch (Exception exception) 
       { 
        if (transaction != null) transaction.Rollback(); 

        throw; 
       } 
       finally 
       { 
        session.Flush(); 
       } 
      } 

     } 
    } 

此代碼工作,直到表有2個LAC記錄。

但在表中增加10次LAC記錄後,此方法將引發一個錯誤:

NHibernate.Util.ADOExceptionReporter |類型'System.OutOfMemoryException'的異常被拋出。

NHibernate.Util.ADOExceptionReporter |類型'System.OutOfMemoryException'的異常被拋出。

NHibernate.Util.ADOExceptionReporter |類型'System.OutOfMemoryException'的異常被拋出。

[DAL.GetBatchRecordsOnBatchId]:Unheld誤差在申請中發生,異常:無法執行查詢 [SELECT this_.ReferenceId如Referenc1_2_0_,this_.AccountNumber如AccountN2_2_0_,this_.AccountStatus如AccountS3_2_0_,this_.AccountType如AccountT4_2_0_ ,this_.AccountSubType如AccountS5_2_0_,this_.AccountDescription如AccountD6_2_0_,this_.ActivationDate如Activati7_2_0_,this_.CombinedBilling如Combined8_2_0_,this_.PlanAmount如PlanAmount2_0_,this_.PlanCode如PlanCode2_0_,this_.CustomerName如Custome11_2_0_,this_.CustomerEmail如Custome12_2_0_,THIS_ .CustomerPhone爲Custome13_2_0_,this_.CustomerAddress爲Custome14_2_0_,this_.CustomerCity爲Custome15_2_0_,this_.CustomerState爲Custome16_2_0_,this_.CustomerZipCode爲Custome17_2_0_,this_.PaymentAmount爲Payment18_2_0_,this_.PaymentCurrency爲Pa yment19_2_0_,this_.PaymentDate爲Payment20_2_0_,this_.TransactionId爲Transac21_2_0_,this_.BatchId爲BatchId2_0_ FROM TIOTestDB.dbo.BatchDetails this_ WHERE this_.BatchId =? ] 位置參數:#0> 3 [SQL:SELECT this_.RefereId如Referenc1_2_0_,this_.AccNumber如AccountN2_2_0_,this_.AcStatus如AccountS3_2_0_,this_.AcType如AccountT4_2_0_,this_.AccSubType如AccountS5_2_0_,this_.AccountDescription如AccountD6_2_0_, this_.ActivationDate如Activati7_2_0_,this_.CombinedBilling如Combined8_2_0_,this_.PlanAmount如PlanAmount2_0_,this_.PlanCode如PlanCode2_0_,this_.CustomerName如Custome11_2_0_,this_.Email如Custome12_2_0_,this_.Phone如Custome13_2_0_,this_.Address如Custome14_2_0_,THIS_。市Custome15_2_0_,this_.State爲Custome16_2_0_,this_.ZipCode爲Custome17_2_0_,this_.PayAmount爲Payment18_2_0_,this_.Currency爲Payment19_2_0_,this_.PayDate爲Payment20_2_0_,this_.TransactionId爲Transac21_2_0_,this_.bhId作爲bhId2_0_ FROM bDetails THIS_ WHERE THIS_ .bhId =?]

因爲我在foreach()迭代中執行此函數, 儘管查詢執行1次或2次並檢索數據,但在此之後它會拋出內存不足異常。作爲一名經驗豐富的NHibernate開發人員,我可以理解我需要重構LINQ查詢來優化其性能。

此外,我已經在互聯網上搜索,但我無法獲得太多的信息。

最早的回覆將不勝感激。

回答

3

首先,您的查詢:

from batchRecords in session.QueryOver<BatchDetails>() 
    .Where(x => x.BatchId == batchId) 
    .List().Skip(stratingRowdId).Take(batchSize) 
select batchRecords 

可以只是簡單:

session.QueryOver<BatchDetails>() 
    .Where(x => x.BatchId == batchId) 
    .List().Skip(stratingRowdId).Take(batchSize) 

,它的行爲完全一樣。您所有的fromselect有效地做的是在查詢的末尾添加.Select(x => x)

現在,你的問題是你打電話List()太早。 List()所做的是將查詢的所有結果檢索到內存中。如果之後使用LINQ方法(就像你使用Skip()Take()),它們將在內存中執行,這不是你想要的。

你應該做的,而不是爲移動List()到查詢的末尾:

session.QueryOver<BatchDetails>() 
    .Where(x => x.BatchId == batchId) 
    .Skip(stratingRowdId).Take(batchSize) 
    .List() 

這樣一來,既Skip()Take()將被轉換成SQL,這意味着你將無法檢索所有的數據存入內存,只有你實際需要的數據。這應該修復你的OOM。

+0

謝謝..它工作 – Riky

相關問題