2012-07-27 17 views
3

所以我已經用盡了爲什麼這是如此緩慢的想法。也許你可以幫忙。 所以我試圖做一個簡單的記錄從一個oracle數據庫使用nHibernate映射的代碼。我正在使用nuget的nHibernate verison 3.3.1.4。簡單得到使用NHibernate(使用映射代碼)是非常緩慢的

這裏是映射代碼:

public class Person 
{ 
    public virtual PersonKey Key { get; set; } 
    public virtual string FirstName { get; set; } 
    public virtual string LastName { get; set; } 
} 

public class PersonKey 
{ 
    public virtual string PersonId { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
      return false; 
     var t = obj as PersonKey; 
     if (t == null) 
      return false; 
     if (PersonId == t.PersonId) 
      return true; 
     return false; 
    } 
    public override int GetHashCode() 
    { 
     return (PersonId).GetHashCode(); 
    } 
} 

public class PersonMap : ClassMapping<Person> 
{ 
    public PersonMap() 
    { 
     Schema("MyDB"); 
     Table("Person"); 
     ComponentAsId(id => id.Key, idMapper => idMapper.Property(p => p.PersonId)); 
     Property(i => i.FirstName); 
     Property(i => i.LastName); 
    } 
} 

下面是創建會話工廠和檢索數據的代碼。

var mapper = new ModelMapper(); 
     var cfg = new Configuration(); 

     mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes()); 

     cfg.DataBaseIntegration(c => 
     { 
      c.ConnectionString = @"User Id=user;Password=password;Data Source=MyDB;"; 
      c.Driver<OracleClientDriver>(); 
      c.Dialect<Oracle10gDialect>(); 

      c.LogSqlInConsole = true; 
      c.LogFormattedSql = true; 
      c.AutoCommentSql = true; 
     }); 

     cfg.AddMapping(mapper.CompileMappingForAllExplicitlyAddedEntities()); 
     var sessionFactory = cfg.BuildSessionFactory(); 

     stopwatch.Stop(); 
     Console.WriteLine("Building session factory: {0}", stopwatch.ElapsedMilliseconds); 
     stopwatch.Restart(); 

     Person entity = null; 

     using (var session = sessionFactory.OpenSession()) 
     using(var tx = session.BeginTransaction()) 
     { 
      entity = (Person) session.Get("Person", new PersonKey(){PersonId = "1"}); 
      tx.Commit(); 
     } 

查詢生成如下:

SELECT person0_.PersonId as PersonId0_0_, 
person0_.FirstName as FirstName0_0_, person0_.LastName as LastName0_0_, 
FROM MyDB.Person person0_ 
WHERE person0_.PersonId=:p0; 
:p0 = '1' 

它需要平均大約80-100秒以訪問所檢索的對象。這也包括創建會話。

所以有些明顯的事情,我找了:

  • 爲PERSONID coloumn被索引(它是表的主鍵)。
  • 數據庫在服務器上,所以要檢查它是不是網絡吃飯的時間,我運行上面生成的查詢使用AD0.Net(Oracleconnection + Oraclecommand)。這大概需要180ms,這包括創建連接並將記錄映射到實體類。
  • 通過PL/SQL開發人員進行查詢(花費大約32ms)。
  • 檢查生成的查詢的查詢計劃(已確認使用索引掃描獨特的,而不是全表掃描)。
  • 我已經在我的本地運行對一個類似規模的SQL2012分貝上面的代碼,並且它的快瘋了incomparison,圍繞180ms的通過NHibernate的代碼。
  • 然nhprof(評估),並得到了以下結果:

Results from NHibernate profiler

好像運行查詢,結果被從數據庫(根據nhprof結果)返回速度非常快,但也許它將查詢的值融合到正在佔用時間的實體中。我茫然地咀嚼着時間!

我的下一步行動是NHibernate的源連接到解決方案,並通過它的一步,但下載的工作訪問是有限的(甚至是GitHub的!)。直到那麼任何想法?

乾杯。

更新:所以我在我的項目中有nHibernate源代碼,並通過它。一切都一直很好,直到程序獲取移動到這段代碼:

for (count = 0; count < maxRows && rs.Read(); count++)    

這是rs.Read()的執行吃掉的時候,其中RS是oracle DataReader的。這段代碼是在Loader.cs文件DoQuery功能。

奇怪的是,如果傳入的查詢是非參數化的動態查詢(例如select ... from person where personid = '1'),則執行快速(〜1ms),但如果其參數化(例如,select ... from person where personid = :p1),那麼它很慢。由於我想利用nHibernate的力量,我需要使用生成的參數化查詢。我仍然試圖找出爲什麼甲骨文讀者

+2

我想你不應該包括創建'SessionFactory'的時間。這很費時,但只需要一次,所以對於所有實際的目的,只檢查'using'語句的時間。 – Yogesh 2012-07-27 06:33:12

+0

嗨,我沒有在底部包含一些代碼,但我已經分別測量了創建會話工廠以及session.get的時間。我所包含的數字僅僅反映了session.get。這段代碼只是一個POC,我清楚地知道使sessionfactory只應用一次。 – 2012-07-28 00:13:46

+0

嘗試從第二次使用它時進行測量。 – 2012-07-28 20:09:02

回答

1

發現問題和解決方案通過深沙阿博客here

從本質上講,在NHibernate的參數化查詢與用於Oracle的Microsoft驅動程序是爲瓶頸的原因。

他繼續分享兩個解決方案:

  1. 更換與Oracle開發的Oracle數據客戶端驅動程序,目前微軟Oracle驅動程序。使用新驅動程序運行相同的查詢消除了性能瓶頸。爲此,您需要在打算啓動查詢的計算機上安裝Oracle數據訪問組件(ODAC)。

  2. 當通過NHibernate在查詢中設置參數時,在查詢VARCHAR列時,使用「query.SetAnsiString」而不是「query.SetParameter」。

我已驗證兩種解決方案,他們都工作。解決方案之一就是我所使用的解決方案,因爲我正在使用按代碼映射,並將查詢生成留給nHibernate。