[NHibernate]N+1 Select查詢問題分析


目錄

寫在前面

文檔與系列文章

N+1 Select查詢問題分析

總結

寫在前面

在前面的文章(延遲加載,立即加載)中都提到了N+1 Select的問題,總覺得理解的很不到位,也請大家原諒,這也是為什么單獨將該問題拿出來做分析的原因。nhibernate的默認Lazy加載方式是解決N+1 select問題的一種方案,而我自身的理解是立即加載可以解決,完全的背道而馳了。寫出那篇文章后,對這個問題,一直念念不忘,總覺得哪地方不對勁。由於我對問題的理解很不透徹,也同樣造成你的誤解,真的很抱歉。

文檔與系列文章

[Nhibernate]體系結構

[NHibernate]ISessionFactory配置

[NHibernate]持久化類(Persistent Classes)

[NHibernate]O/R Mapping基礎

[NHibernate]集合類(Collections)映射 

[NHibernate]關聯映射

[NHibernate]Parent/Child

[NHibernate]緩存(NHibernate.Caches)

[NHibernate]NHibernate.Tool.hbm2net

[NHibernate]Nullables

[NHibernate]Nhibernate如何映射sqlserver中image字段

[NHibernate]基本配置與測試 

[NHibernate]HQL查詢 

[NHibernate]條件查詢Criteria Query

[NHibernate]增刪改操作

[NHibernate]事務

[NHibernate]並發控制

[NHibernate]組件之依賴對象

[NHibernate]一對多關系(級聯刪除,級聯添加)

[NHibernate]一對多關系(關聯查詢)

[NHibernate]多對多關系(關聯查詢)

[NHibernate]延遲加載

[NHibernate]立即加載

[NHibernate]視圖處理

N+1 Select查詢問題分析

使用sql查詢數據的時候,如果select太多,勢必也會對數據庫造成壓力,影響性能。比如如果查詢n個Customer對象,則一次查詢獲得所有的customer對象,然后根據customerid查詢關聯的Order表。(立即加載的情況下

一個例子

 1         /// <summary>
 2         /// NHibernateUtil方式,立即加載客戶信息及關聯的數據
 3         /// </summary>
 4         /// <param name="customerID"></param>
 5         /// <returns></returns>
 6         public Customer GetCustomerByImmediatelyLoadNHibernateUtil(Guid customerID)
 7         {
 8             //獲得ISession實例
 9             //通過using的方式將session釋放,為了保證是立即加載的數據,而不是延遲加載的
10             //還記得上篇文章中提到的在延遲加載中,在關閉session情況下,再讀取數據的時候就會有一個異常信息
11             //忘記的可以再回到上一篇文章進行查看
12             using (ISession session = NHibernateHelper.GetSession())
13             {
14                 Customer customer = session.Get<Customer>(customerID);
15                 //
16                 // 摘要: 
17                 //     Force initialization of a proxy or persistent collection.
18                 //
19                 NHibernate.NHibernateUtil.Initialize(customer.Orders);
20                 return customer;
21             }
22         }

這里使用NHinernateUtil實用類進行強制立即加載方式,測試代碼

1         protected void btnImmediately_Click(object sender, EventArgs e)
2         {
3             Business.CustomerBusiness customerBusiness = new Business.CustomerBusiness();
4             Customer customer = customerBusiness.GetCustomerByImmediatelyLoadNHibernateUtil(new Guid("B0720295-9541-40B3-9994-610066224DB8"));
5             bool isInitOrder = NHibernate.NHibernateUtil.IsInitialized(customer.Orders);
6         }

查看生成的sql語句

本來我們是想查詢customer,一次查詢就夠,可是通過監視到的sql,發現多了一次sql查詢,也就是查詢customer的關聯數據表的數據。

而在延遲加載的情況下,則會在需要的時候才會去查詢,性能上面更好。(有關延遲加載的內容,請在系列文章中查找,這里不再贅述了)

如果采用延遲加載方式,生成的sql如下(借用延遲加載文章中的圖說明)

一對多關系Lazy加載

多對多關系Lazy加載

order和Product多對多關系,此時生成的sql語句

你可以看到此時生成的sql語句是通過left outer join(左外連接)進行關聯數據表的,而此時只生成一條sql語句,明顯減少了查詢數據的次數。

總結

(1)select語句的數目太多,需要頻繁的訪問數據庫,會影響檢索性能。此時可采用sql中的左外連接查詢,在一條sql語句中將所有數據查詢出來,並且減少了select的次數。
(2)在應用邏輯只需要訪問Customer對象,而不需要訪問Order對象的場合,加載Order對象完全是多余的操作,這些多余的Order對象白白浪費了許多內存空間。
為了解決以上問題,Hibernate提供了其他兩種檢索策略:延遲檢索策略和迫切左外連接檢索策略。延遲檢索策略能避免多余加載應用程序不需要訪問的關聯對象,迫切左外連接檢索策略則充分利用了SQL的外連接查詢功能,能夠減少select語句的數 

這里就N+1 select問題做一下特別說明,有問題,如果不想辦法解決,總覺得有個疙瘩,早解決,早有好心情。通過本篇的分析,你是不是也對n+1的問題豁然開朗?這也怪我了,當時對那一塊理解確實有誤,再次感到很抱歉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM