在本文中,您將了解 N 1 查詢、如何使用 AppSignal 檢測它們,以及如何修復它們以顯著加快 Django 應用程式的速度。
我們將從理論方面開始,然後轉向實際範例。實際範例將反映您在生產環境中可能遇到的場景。
讓我們開始吧!
什麼是 N 1 查詢?
N 1 查詢問題是與資料庫互動的 Web 應用程式中普遍存在的效能問題。這些查詢可能會導致嚴重的瓶頸,並且隨著資料庫的成長而加劇。
當您檢索物件集合,然後存取集合中每個項目的相關物件時,就會出現問題。例如,取得書籍清單需要單一查詢(1 個查詢),但存取每本書的作者會觸發每個項目的額外查詢(N 個查詢)。
在資料庫中建立或更新資料時也可能會出現 N 1 問題。例如,透過循環迭代來單獨建立或更新對象,而不是使用bulk_create() 或bulk_update() 等方法,可能會導致過多的查詢。
N 1 查詢效率極低,因為執行大量小查詢比將操作合併為更少、更大的查詢要慢得多,而且更耗費資源。
Django 的預設 QuerySet 行為可能會無意中導致 N 1 問題,特別是如果您不知道 QuerySet 是如何運作的。 Django 中的查詢集是惰性的,這表示在對查詢集求值之前不會執行任何資料庫查詢。
先決條件
確保您擁有:
- Python 3.9 和 Git 安裝在本機上
- 支援 AppSignal 的作業系統
- AppSignal 帳號
注意:此專案的原始程式碼可以在 appsignal-django-n-plus-one GitHub 儲存庫中找到。
項目設定
我們將使用圖書管理網路應用程式。該 Web 應用程式旨在演示 N 1 查詢問題以及如何解決它。
先複製 GitHub 儲存庫的基礎分支:
$ git clone git@github.com:duplxey/appsignal-django-n-plus-one.git \ --single-branch --branch base && cd appsignal-django-n-plus-one
接下來,建立並啟動虛擬環境:
$ python3 -m venv venv && source venv/bin/activate
安裝要求:
(venv)$ pip install -r requirements.txt
遷移並填入資料庫:
(venv)$ python manage.py migrate (venv)$ python manage.py populate_db
最後,啟動開發伺服器:
(venv)$ python manage.py runserver
開啟您最喜歡的網頁瀏覽器並導航至 http://localhost:8000/books。 Web 應用程式應從資料庫傳回包含 500 本書的 JSON 清單。
Django 管理網站可透過 http://localhost:8000/admin 存取。管理員憑證是:
user: username pass: password
為 Django 安裝 AppSignal
要在 Django 專案上安裝 AppSignal,請依照官方文件操作:
- AppSignal Python 安裝
- AppSignal Django 工具
- AppSignal SQLite 工具
透過重新啟動開發伺服器確保一切正常:
$ git clone git@github.com:duplxey/appsignal-django-n-plus-one.git \ --single-branch --branch base && cd appsignal-django-n-plus-one
您的應用程式應自動向 AppSignal 發送演示錯誤。從此時起,您的所有錯誤都會傳送到 AppSignal。此外,AppSignal 將監控您應用程式的效能並偵測任何問題。
網路應用程式邏輯
修正 N 1 查詢的先決條件是了解應用程式的資料庫架構。密切注意模型的關係:它們可以幫助您找出潛在的 N 1 問題。
型號
Web 應用程式有兩個模型 - 作者和書籍 - 它們共享一對多 (1:M) 關係。這意味著每本書都與一個作者相關聯,而一個作者可以連結到多本書。
兩個模型都有一個 to_dict() 方法,用於將模型實例序列化為 JSON。最重要的是,Book 模型使用深度序列化(序列化書籍以及書籍的作者)。
模型在 books/models.py 中定義:
$ python3 -m venv venv && source venv/bin/activate
然後它們在 books/admin.py 中註冊 Django 管理站點,如下所示:
(venv)$ pip install -r requirements.txt
請注意,AuthorAdmin 使用 BookInline 在作者的管理頁面中顯示作者的書籍。
意見
網路應用程式提供以下端點:
- /books/ 回傳書籍清單
-
/books/
/ 回傳特定書籍 - /books/by-authors/ 傳回按作者分組的書籍清單
- /books/authors/ 返回作者列表
-
/books/authors/
/ 回傳特定作者
如果您正在執行開發網頁伺服器,則可以點擊上面的連結。
它們在 books/views.py 中定義如下:
(venv)$ python manage.py migrate (venv)$ python manage.py populate_db
太棒了,您現在知道網頁應用程式是如何運作的!
在下一節中,我們將對我們的應用程式進行基準測試,以使用 AppSignal 檢測 N 1 個查詢,然後修改程式碼以消除它們。
使用 AppSignal 偵測 Django 應用程式中的 N 1 查詢
使用 AppSignal 檢測效能問題很容易。您所要做的就是像平常一樣使用/測試應用程式(例如,透過存取所有端點並驗證回應來執行最終用戶測試)。
當某個端點被命中時,AppSignal 將為其建立一份效能報告,並將所有相關存取分組在一起。每次訪問都將作為樣本記錄在端點的報告中。
偵測檢視中的 N 1 個查詢
首先,訪問您應用程式的所有端點以產生效能報告:
- /書籍/
- /books/
/ - /書籍/作者/
- /書籍/作者/
- /books/authors/
/
接下來,讓我們使用 AppSignal 儀表板來分析慢速端點。
範例 1:一對一關係 (select_lated())
導覽至您的 AppSignal 應用程式並選擇 效能 >側邊欄上的問題清單。然後按一下平均值 以平均回應時間降序對問題進行排序。
點擊最慢的端點(books/)查看其詳細資訊。
查看最新範例,我們可以看到該端點在 1090 毫秒內回傳回應。群組細分顯示 SQLite 需要 651 毫秒,而 Django 需要 439 毫秒。
這表示有問題,因為像這樣簡單的端點不應該花費那麼長的時間。
要獲取有關所發生事件的更多詳細信息,請選擇側邊欄中的範例,然後選擇最新範例。
向下捲動到事件時間軸以查看執行了哪些 SQL 查詢。
將滑鼠停留在 query.sql 文字上會顯示實際的 SQL 查詢。
執行了超過 1000 個查詢:
$ git clone git@github.com:duplxey/appsignal-django-n-plus-one.git \ --single-branch --branch base && cd appsignal-django-n-plus-one
這些是 N 1 個查詢的明顯標誌。第一個查詢取得一本書 (1),隨後的每個查詢取得該書的作者詳細資料 (N)。
要修復它,請導航至 books/views.py 並修改 book_list_view(),如下所示:
$ python3 -m venv venv && source venv/bin/activate
透過利用 Django 的 select_lated() 方法,我們在初始查詢中選擇附加的相關物件資料(即作者)。 ORM 現在將利用 SQL 連接,最終查詢將如下所示:
(venv)$ pip install -r requirements.txt
等待開發伺服器重新啟動並重新測試受影響的端點。
再次進行基準測試後,回應時間從 1090 減少到 45,查詢數量從 1024 減少到 2。分別提高了 24 倍和 512 倍。
範例 2:多對一關係 (prefetch_lated())
接下來,讓我們來看看第二慢的端點(books/by-authors/)。
像我們在上一個步驟中所做的那樣使用儀表板來檢查端點的 SQL 查詢。您會注意到此端點有類似但不太嚴重的 N 1 模式。
這個端點的效能較不嚴重,因為 Django 夠聰明,可以快取頻繁執行的 SQL 查詢,也就是重複取得一本書的作者。查看官方文件以了解有關 Django 快取的更多資訊。
讓我們利用 books/views.py 中的 prefetch_lated() 來加速端點:
$ git clone git@github.com:duplxey/appsignal-django-n-plus-one.git \ --single-branch --branch base && cd appsignal-django-n-plus-one
在上一節中,我們使用 select_lated() 方法來處理一對一關係(每本書都有一個作者)。然而,在本例中,我們正在處理一對多關係(一個作者可以擁有多本書),因此我們必須使用 prefetch_lated()。
這兩種方法的區別在於 select_lated() 工作在 SQL 級別,而 prefetch_lated() 則在 Python 級別進行最佳化。後一種方法也可以用於多對多關係。
有關更多信息,請查看 Django 關於 prefetch_lated() 的官方文檔。
基準測試後,回應時間從 90 毫秒減少到 44 毫秒,查詢數量從 32 減少到 4。
在 Django Admin 中偵測 N 1 個查詢
在 Django 管理網站中發現 N 1 個查詢的工作原理類似。
首先,登入您的管理網站並產生績效報告(例如,建立一些作者或書籍,更新和刪除它們)。
接下來,導覽到您的 AppSignal 應用程式儀表板,這次由管理員過濾問題:
就我而言,兩個最慢的端點是:
- /管理/登入
- /admin/books/author/
我們無法對 /admin/login 做太多事情,因為它完全由 Django 處理,所以讓我們專注於第二個最慢的端點。檢查它會發現 N 1 查詢問題。每本書都會單獨取得作者。
要解決此問題,請重寫 BookInline 中的 get_queryset() 以在初始查詢中取得作者詳細資訊:
$ python3 -m venv venv && source venv/bin/activate
再次進行基準測試並驗證查詢數量是否有減少。
總結
在這篇文章中,我們討論了使用 AppSignal 檢測和修復 Django 中的 N 1 個查詢。
利用您在這裡學到的知識可以幫助您大幅加快 Django Web 應用程式的速度。
要記住的兩個最重要的方法是 select_lated() 和 prefetch_lated()。第一個用於一對一關係,第二個用於一對多和多對多關係。
編碼愉快!
P.S.如果您想在 Python 文章發布後立即閱讀,請訂閱我們的 Python Wizardry 時事通訊,不錯過任何一篇文章!
以上是使用 AppSignal 在 Django 中尋找並修復 N ueries的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Python在web開發、數據科學、機器學習、自動化和腳本編寫等領域有廣泛應用。 1)在web開發中,Django和Flask框架簡化了開發過程。 2)數據科學和機器學習領域,NumPy、Pandas、Scikit-learn和TensorFlow庫提供了強大支持。 3)自動化和腳本編寫方面,Python適用於自動化測試和系統管理等任務。

兩小時內可以學到Python的基礎知識。 1.學習變量和數據類型,2.掌握控制結構如if語句和循環,3.了解函數的定義和使用。這些將幫助你開始編寫簡單的Python程序。

如何在10小時內教計算機小白編程基礎?如果你只有10個小時來教計算機小白一些編程知識,你會選擇教些什麼�...

使用FiddlerEverywhere進行中間人讀取時如何避免被檢測到當你使用FiddlerEverywhere...

Python3.6環境下加載Pickle文件報錯:ModuleNotFoundError:Nomodulenamed...

如何解決jieba分詞在景區評論分析中的問題?當我們在進行景區評論分析時,往往會使用jieba分詞工具來處理文�...

如何使用正則表達式匹配到第一個閉合標籤就停止?在處理HTML或其他標記語言時,常常需要使用正則表達式來�...

攻克Investing.com的反爬蟲策略許多人嘗試爬取Investing.com(https://cn.investing.com/news/latest-news)的新聞數據時,常常�...


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

WebStorm Mac版
好用的JavaScript開發工具

禪工作室 13.0.1
強大的PHP整合開發環境

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中