[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);或許在單檔維護的情況下看不出效能怎樣,
但在大量存取這種分毫都要計較的情況下,這可以幫忙帶來些許的效能進步