[NHibernate]大量存取時要注意的地方

[NHibernate]大量存取時要注意的地方

在替系統做效能調整時,發現NHibernate有幾個小地方若是沒有注意到的話,會讓效能越來越慢

 

情境一 : 有使用到OpensessionInView或是SessionScope去延長NHibernate Session存活的時間時,在這個時間下大量存取資料

   1:              using (new SessionScope())
   2:              {
   3:                  // 假設在data裡有一萬筆Person
   4:                  foreach (IPerson person in data) 
   5:                  {
   6:                      //然後把這一萬筆Person存進DB裡  
   7:                      PersonService.Create(person);
   8:                  }
   9:              }

以這個單純的情境來看,由於session一直都沒被釋放掉,所以每存一筆Person,Session就要去記住它,

當筆數越多session要記的Person就越多,所以效能也就會隨著筆數的增加而越來差。

若改成這樣:

   1:              foreach (IPerson person in data)
   2:              {
   3:                  using (new SessionScope())
   4:                  {
   5:                      //然後把這一萬筆Person存進DB裡  
   6:                      PersonService.Create(person);
   7:                  }
   8:              }
每存完一個人就釋放掉的話,就可以穩定效能了。(範例過於簡單請不要太認真)
 

情境二  : 在複雜的關聯下,存多次不如存一次 

 

   1:                  IPerson person = PersonService.MakeParty();
   2:                  IPersonAccount personAccount = this.PersonAccountService.MakePartyRole(person);
   3:                  // 建立person 跟 personAccount
   4:                  PersonService.CreateOrUpdate(person);
   5:                  
   6:                  IMobilePhone phone = RheaFactory.DomainFactory.MakeDomain<IMobilePhone>();
   7:                  person.ContactMechs.Add(phone);
   8:                  phone.Party = person;
   9:                  // 建立person 跟 mobilePhone
  10:                  ContactMechService.CreateOrUpdate(phone);
  11:   
  12:                  IEmail email = RheaFactory.DomainFactory.MakeDomain<IEmail>();
  13:                  person.ContactMechs.Add(email);
  14:                  email.Party = person;
  15:                  // 建立person 跟 email
  16:                  ContactMechService.CreateOrUpdate(email);
  17:   
  18:                  IPostalAddress addr = RheaFactory.DomainFactory.MakeDomain<IPostalAddress>();
  19:                  person.ContactMechs.Add(addr);
  20:                  addr.Party = person;
  21:                  // 建立person 跟 postalAddress
  22:                  ContactMechService.CreateOrUpdate(addr);
  23:   
  24:                  IWorkingCareer work = RheaFactory.DomainFactory.MakeDomain<IWorkingCareer>();
  25:                  personAccount.WorkingCareers.Add(work);
  26:                  work.PersonAccount = personAccount;
  27:   
  28:                  ICustomerAnniversary anniversary = RheaFactory.DomainFactory.MakeDomain<ICustomerAnniversary>();
  29:                  personAccount.CustomerAnniversaries.Add(anniversary);
  30:                  // 建立personAccount 跟 WorkingCareer & anniversary
  31:                  PersonAccountService.CreateOrUpdate(personAccount);
 
這個範例程式每增加一組關聯就會存到DB一次,一般用NHibernate一定不會這樣用這是挺誇張的寫法,
不過或許會有中間存一次到兩次的情況,以前我一直覺得其實Persistence回DB的動作一次跟多次應該沒什麼差別,
但這中間其實是會有些微的差異,另外隨著Domain Model物件關聯的設計,也會對這種多次存的動作帶來效能上的差異
以這次調整的心得是,如在做複雜的關聯時,Persistence 的次數越少越好,最好能所有物件都設好後Persistence一次就行
 
如下:
 
 
   1:  IPerson person = PersonService.MakeParty();
   2:  IPersonAccount personAccount = this.PersonAccountService.MakePartyRole(person);
   3:            
   4:  IMobilePhone phone = RheaFactory.DomainFactory.MakeDomain<IMobilePhone>();
   5:  person.ContactMechs.Add(phone);
   6:  phone.Party = person;
   7:   
   8:  IEmail email = RheaFactory.DomainFactory.MakeDomain<IEmail>();
   9:  person.ContactMechs.Add(email);
  10:  email.Party = person;
  11:   
  12:  IPostalAddress addr = RheaFactory.DomainFactory.MakeDomain<IPostalAddress>();
  13:  person.ContactMechs.Add(addr);
  14:  addr.Party = person;
  15:   
  16:  IWorkingCareer work = RheaFactory.DomainFactory.MakeDomain<IWorkingCareer>();
  17:  personAccount.WorkingCareers.Add(work);
  18:  work.PersonAccount = personAccount;
  19:   
  20:  ICustomerAnniversary anniversary = RheaFactory.DomainFactory.MakeDomain<ICustomerAnniversary>();
  21:  personAccount.CustomerAnniversaries.Add(anniversary);
  22:   
  23:  // 上面都在做關聯,最後在用主要的那顆物件去Persistence就行
  24:  PersonService.CreateOrUpdate(person);
 
或許在單檔維護的情況下看不出效能怎樣,
但在大量存取這種分毫都要計較的情況下,這可以幫忙帶來些許的效能進步