Django-ORM-prefetch_related

Django-ORM-prefetch_related

  • 模型定義
    • N+1 查詢問題示例
  • 使用 prefetch_related 優化查詢
  • 處理更復雜的查詢
    • 示例:預取特定條件的書籍
    • 示例:預取多個關聯字段
  • 性能比較
  • 注意事項
  • 總結

通過 AuthorBooks 兩個模型來理解 Django 的 prefetch_related 方法。
探討如何使用 prefetch_related 來優化查詢,避免 N+1 查詢問題,
并展示其在處理多對多關系和復雜查詢中的強大功能。

模型定義

首先,假設我們有兩個模型:AuthorBook。一個作者可以寫多本書,一本書也可以有多個作者(多對多關系)。

from django.db import modelsclass Author(models.Model):name = models.CharField(max_length=100)def __str__(self):return self.nameclass Book(models.Model):title = models.CharField(max_length=100)authors = models.ManyToManyField(Author, related_name='books')def __str__(self):return self.title

N+1 查詢問題示例

假設我們想要獲取所有作者以及他們所寫的書籍。
如果不使用 prefetch_related,可能會遇到 N+1 查詢問題。

# 獲取所有作者
authors = Author.objects.all()for author in authors:print(f"Author: {author.name}")for book in author.books.all():  # 每個作者都會觸發一次數據庫查詢print(f"  Book: {book.title}")

問題分析:
? 第一次查詢獲取所有作者。
? 對于每個作者,執行一次查詢來獲取其書籍。
? 如果有 10 個作者,總共會執行 1 + 10 = 11 次查詢。

使用 prefetch_related 優化查詢

prefetch_related 可以顯著減少查詢次數。
它會在后臺執行額外的查詢,并將結果緩存起來,
以便在訪問關聯對象時不需要額外的數據庫查詢。

# 使用 prefetch_related 預取每個作者的書籍
authors = Author.objects.prefetch_related('books')for author in authors:print(f"Author: {author.name}")for book in author.books.all():  # 現在只執行兩次查詢print(f"  Book: {book.title}")

優化效果:
? 第一次查詢獲取所有作者。
? 第二次查詢獲取所有相關的書籍。
? Django 在 Python 層面將這些書籍分配給相應的作者。
? 總共只執行了 2 次查詢,無論有多少個作者。

處理更復雜的查詢

有時候,我們可能需要預取多個關聯字段,或者對預取的數據進行過濾。
這時,可以使用 Prefetch 對象來實現更細粒度的控制。

示例:預取特定條件的書籍

假設我們只想預取每位作者最近出版的 5 本書:

from django.db.models import Prefetch# 定義一個 Prefetch 對象,過濾并限制預取的書籍數量
recent_books = Prefetch('books',queryset=Book.objects.order_by('-id')[:5], # 假設 id 越大,出版時間越近to_attr='recent_books'                     # 將預取的書籍存儲在 author.recent_books 中
)authors = Author.objects.prefetch_related(recent_books)for author in authors:print(f"Author: {author.name}")for book in author.recent_books:  # 訪問預取的書籍print(f"  Recent Book: {book.title}")

解釋:
? 使用 Prefetch 對象,我們可以自定義預取的查詢集。
? to_attr 參數指定了預取的數據存儲在模型實例的哪個屬性中。
? 這樣可以避免加載所有關聯對象,只加載我們需要的部分。

示例:預取多個關聯字段

如果 Author 模型還有其他關聯字段,比如 editor,我們可以同時預取多個關聯:

authors = Author.objects.prefetch_related('books','editor'  # 假設有一個 ForeignKey 字段 'editor'
)for author in authors:print(f"Author: {author.name}")for book in author.books.all():print(f"  Book: {book.title}")if author.editor:print(f"  Editor: {author.editor.name}")

性能比較

為了更直觀地理解 prefetch_related 的性能優勢,我們來看一個簡單的性能對比:

import time# 不使用 prefetch_related
start_time = time.time()
authors = Author.objects.all()
for author in authors:for book in author.books.all():pass  # 模擬操作
end_time = time.time()
print(f"無 prefetch_related 查詢次數: {end_time - start_time} 秒")# 使用 prefetch_related
start_time = time.time()
authors = Author.objects.prefetch_related('books')
for author in authors:for book in author.books.all():pass  # 模擬操作
end_time = time.time()
print(f"使用 prefetch_related 查詢次數: {end_time - start_time} 秒")

預期結果:
? 不使用 prefetch_related 的情況下,查詢時間會隨著作者數量的增加而線性增長。
? 使用 prefetch_related 后,查詢時間基本保持不變,因為關聯數據的查詢次數大大減少。

注意事項

  1. 適用場景prefetch_related 主要用于處理“多對多”和“一對多”關系。對于“一對一”或“外鍵”關系,通常使用 select_related 更為高效。

  2. 內存消耗:由于 prefetch_related 會將所有預取的數據加載到內存中,如果關聯數據量非常大,可能會導致內存占用過高。因此,在處理大數據集時需要謹慎使用。

  3. 自定義查詢:通過 Prefetch 對象,可以自定義預取的查詢集,如過濾、排序或限制數量,從而進一步優化性能。

  4. 鏈式調用prefetch_related 可以與其他查詢優化方法(如 filterexclude 等)結合使用,以滿足復雜的查詢需求。

總結

prefetch_related 是 Django ORM 提供的一個強大的查詢優化工具,特別適用于處理多對多和一對多關系中的 N+1 查詢問題。通過預先加載關聯對象,prefetch_related 能夠顯著減少數據庫查詢次數,提高應用的性能。在使用時,需要根據具體的業務場景選擇合適的預取策略,并注意內存消耗等問題,以達到最佳的優化效果。

希望通過以上的解釋和示例,你對 django-prefetch_related 有了更深入的理解!

Django-ORM-prefetch_related

  • 模型定義
    • N+1 查詢問題示例
  • 使用 prefetch_related 優化查詢
  • 處理更復雜的查詢
    • 示例:預取特定條件的書籍
    • 示例:預取多個關聯字段
  • 性能比較
  • 注意事項
  • 總結

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/73043.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/73043.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/73043.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Boot3整合Knife4j(4.5.0)

整體概述 Spring Boot 是用于簡化 Spring 應用開發的框架,通過自動配置和約定大于配置原則,能讓開發者快速搭建和運行 Spring 應用。Knife4j 是基于 Swagger 增強的 API 文檔生成工具,可方便展示和調試 API 接口,生成美觀易用的 …

Java 大視界 -- 區塊鏈賦能 Java 大數據:數據可信與價值流轉(84)

💖親愛的朋友們,熱烈歡迎來到 青云交的博客!能與諸位在此相逢,我倍感榮幸。在這飛速更迭的時代,我們都渴望一方心靈凈土,而 我的博客 正是這樣溫暖的所在。這里為你呈上趣味與實用兼具的知識,也…

K8S學習之基礎二十四:k8s的持久化存儲之pv和pvc

K8S的存儲之pv和pvc 在 Kubernetes (k8s) 中,持久化存儲是通過 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 來實現的。PVC 是用戶對存儲資源的請求,而 PV 是集群中的實際存儲資源。PVC 和 PV 的關系類似于 Pod 和 Node 的關系。 Persisten…

【Hive】Hive安裝

Hive 第一章 Hive的基礎知識 第二章 Hive安裝 第三章 DDL(Data Definition Language)數據定義 第四章 DML(Data Manipulation Language)數據操作 第五章 Hive查詢 第六章 Hive的基礎知識 第七章 Hive函數 第八章 分區表和分桶表 …

關于C/C++語言的初學者在哪刷題,怎么刷題

引言: 這篇博客主要是針對初學者關于怎么在網上刷題,以及在哪里刷題。 1.介紹平臺(在哪刷題): 1.牛客牛客網https://www.nowcoder.com/ :有許多面試題,也有許多供學習者練習的題 2.洛谷洛谷 …

k8s面試題總結(十四)

什么是Helm? Helm是一個k8s的包管理工具,它簡化了應用程序在k8s集群中的部署,管理和維護。類似于rpm包和yum之間的關系。 K8s傳統方式:類似于rpm安裝包的方式,逐步進行安裝,遇到依賴還得解決依賴問題 he…

物理服務器的作用都有哪些?

物理服務器是一種高性能的專用服務器,一般會被運用在大型組織和云計算環境當中,可以為企業和用戶提供數據存儲和計算資源,幫助企業提高整體的工作效率和快速實現業務目標。 物理服務器有著較高的安全性,企業可以將重要的數據信息備…

01 音視頻知識學習(視頻)

圖像基礎概念 ?像素:像素是一個圖片的基本單位,pix是英語單詞picture的簡寫,加上英 語單詞“元素element”,就得到了“pixel”,簡稱px,所以“像素”有“圖像元素” 之意。 ? 分辨率:是指圖像…

有關MyBatis的動態SQL

有關MyBatis動態SQL MyBatis動態SQL是一種根據不同條件靈活拼接SQL語句的技術,基于OGNL表達式實現。動態 SQL 大大減少了編寫代碼的工作量,更體現了 MyBatis 的靈活性、高度可配置性和可維護性。 1.什么是動態SQL? 動態sql可以在一些需要靈活拼接sql…

react使用拖拽,縮放組件,采用react-rnd解決 -完整版

屏幕錄制2025-03-10 10.16.06 以下代碼僅提供左側可視化區域 右側數據根據你們的存儲數據來 大家直接看Rnd標簽設置的屬性即可!!!!! /*** 用戶拖拽水印的最終位置信息*/ export interface ProductWatermarkValue {wat…

Spring Cloud之遠程調用OpenFeign參數傳遞

目錄 OpenFeign參數傳遞 傳遞單個參數 傳遞多個參數 傳遞對象 傳遞JSON OpenFeign參數傳遞 傳遞單個參數 服務提供方product-service RequestMapping("/product") RestController public class ProductController {Autowiredprivate ProductService productSe…

每日一練之移除鏈表元素

題目: 畫圖解析: 方法:雙指針 解答代碼(注:解答代碼帶解析): //題目給的結構體 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* }…

從零開始的python學習(五)P75+P76+P77+P78+P79+P80

本文章記錄觀看B站python教程學習筆記和實踐感悟,視頻鏈接:【花了2萬多買的Python教程全套,現在分享給大家,入門到精通(Python全棧開發教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p6&share_sourcecopy_web&v…

基于SpringBoot實現旅游酒店平臺功能八

一、前言介紹: 1.1 項目摘要 隨著社會的快速發展和人民生活水平的不斷提高,旅游已經成為人們休閑娛樂的重要方式之一。人們越來越注重生活的品質和精神文化的追求,旅游需求呈現出爆發式增長。這種增長不僅體現在旅游人數的增加上&#xff0…

FastAPI 分頁模塊實現詳解

1. 簡介 本文詳細介紹了一個基于 FastAPI 框架的通用分頁處理模塊的實現。該模塊提供了標準的分頁參數處理、數據切片和響應格式化功能,可以輕松地集成到任何 FastAPI 項目中。 2. 代碼實現 2.1 導入必要的模塊 首先,我們需要導入所需的模塊&#xf…

Java 學習記錄:基礎到進階之路(一)

今天,讓我們深入到 Java 項目構建、基礎語法及核心編程概念的領域,一探究竟。 軟件安裝及環境配置請查看之前更新的博客有著詳細的介紹: IDEA軟件安裝&環境配置&中文插件-CSDN博客 目錄 1.Java 項目構建基礎 1.項目中的 SRC 目錄…

Yashan DB 對象管理

一、什么是數據庫對象 數據庫對象是數據庫里面用來存儲和指向數據的各種概念和結構的總稱。數據庫支持的對象包括: ? 表:表是一個邏輯概念,是數據庫組織管理數據的基本單位。 ? 索引:索引是建立在表上的邏輯對象,索…

deepseek 3FS編譯

3FS在ubuntu22.04下的編譯(記錄下編譯過程,方便后續使用) 環境信息 OS ubuntu 22.04內核版本 6.8.0-52-genericlibfuse 3.16.1rust 1.75.0FoundationDB 7.1.66meson 1.0.0ninja 1.10.1 libfuse編譯 以下建議均在root下執行 pip3 install…

python-uiautomator2 安裝教程

目錄 一、簡介 二、支持平臺及語言 三、工作原理 四、安裝 一、簡介 uiautomator2是一個python庫,用于Android的UI自動化測試,其底層基于Google uiautomator,Google提供的uiautomator庫可以獲取屏幕上任意一個APP的任意一個控件屬性&…

無頭瀏覽器與請求簽名技術-Cloudflare防護

在實際數據采集實踐中,許多目標網站(例如 Amazon)都會采用 Cloudflare 等防護措施,防止機器人和非正常流量。本文將分享一個故障場景下的排查與改進方案,講述如何利用無頭瀏覽器、請求簽名技術以及爬蟲代理 IP來實現數…