如果您正在閱讀這篇文章,您可能正在Django開發中遇到N+1問題,或者在以前的某個時候遇到過這個問題。由於這個問題,頁面加載速度變慢,您可能會發現select_relatedprefetch_related的解決方案。

首先,歡迎來到我的博客!🎉 如果您讀完這篇文章,您肯定會掌握有效解決N+1問題的方法。

如果您還不完全了解N+1問題的概念,我建議您先閱讀下面的文章。

Django ORM中的N+1問題是什麼?為什麼會發生?

🔍 在Django中解決N+1問題的兩種方法

Django ORM提供select_relatedprefetch_related兩種功能來解決N+1問題。但是這兩種功能的工作方式不同,因此準確理解在什麼情況下使用它們是非常重要的。

📌 select_relatedprefetch_related的共同原理

這兩種方法的核心共同原理是在第一個查詢中一次性從資料庫中提取所需的欄位,以便在Django內部高效利用所提取的數據

例如,想像一下您去大型超市購買材料來製作蛋糕,您一次性購買了麵粉、鮮奶油、水果等所需的所有材料。回到家開始烹飪時,所有材料都已經準備好了,因此可以立即開始烹飪。

但是如果需要逐一去購買材料會怎樣?您去購買麵粉,回來後想開始揉麵糰,但發現沒有鮮奶油,只好再次去超市。再回來後想開始工作,這次又發現缺少水果,又要去市場,那麼呢?

這種方式會使得烹飪過程非常耗時。在Django ORM中,select_relatedprefetch_related的作用是避免這種無效率的數據調用,幫助您一次提取所需的數據,快速處理

Django ORM中的Select Related與Prefetch Related

✅ 1. select_related – 使用SQL JOIN進行即時加載

用於ForeignKey(1:N)關係

  • 使用SQL JOIN一次查詢提取數據
  • 由於立即提取相關對象,因此不需要額外的資料庫請求

📌 select_related使用範例

authors = Author.objects.select_related('post_set').all()

🧐 當select_related未被應用時執行的SQL

SELECT * FROM author;
SELECT * FROM post WHERE author_id = 1;
SELECT * FROM post WHERE author_id = 2;
...

🚀 當應用select_related時執行的SQL

SELECT * FROM author INNER JOIN post ON author.id = post.author_id;

✅ 2. prefetch_related – 使用個別查詢進行預加載

用於ManyToMany和反向ForeignKey關係

  • 執行個別查詢後,Django在Python中優化並連接數據
  • 由於不使用SQL JOIN,處理大數據時可能更有利

📌 prefetch_related使用範例

authors = Author.objects.prefetch_related('post_set').all()

🧐 prefetch_related應用後執行的SQL

SELECT * FROM author;
SELECT * FROM post WHERE author_id IN (1, 2, 3, 4, 5, ...);

🎯 總結 – 這樣就能解決N+1問題!

在使用Django ORM時,如果忽略N+1問題,性能可能會顯著下降。但是只要適當利用select_relatedprefetch_related,您可以將SQL執行次數降到最低,大幅提升頁面加載速度。

✅ 彙整

  • 在ForeignKey(1:N)關係下,使用select_related
  • 在ManyToMany或反向參考關係下,使用prefetch_related
  • 無論如何,都需要檢查執行的SQL並進行優化
  • 如果查詢執行速度變慢,應懷疑是否存在N+1問題

📌 相關文章也請參考!

Django ORM中的N+1問題是什麼?為什麼會發生?

現在,利用select_relatedprefetch_related來解決N+1問題吧!🚀 如果您有任何疑問或需要更多信息,請隨時在下方留言。😊