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