首頁 > 後端開發 > Python教學 > 使用 AppSignal 在 Django 中尋找並修復 N ueries

使用 AppSignal 在 Django 中尋找並修復 N ueries

DDD
發布: 2024-12-22 21:10:39
原創
781 人瀏覽過

在本文中,您將了解 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 在作者的管理頁面中顯示作者的書籍。

意見

網路應用程式提供以下端點:

  1. /books/ 回傳書籍清單
  2. /books// 回傳特定書籍
  3. /books/by-authors/ 傳回按作者分組的書籍清單
  4. /books/authors/ 返回作者列表
  5. /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 個查詢

首先,訪問您應用程式的所有端點以產生效能報告:

  1. /書籍/
  2. /books//
  3. /書籍/作者/
  4. /書籍/作者/
  5. /books/authors//

接下來,讓我們使用 AppSignal 儀表板來分析慢速端點。

範例 1:一對一關係 (select_lated())

導覽至您的 AppSignal 應用程式並選擇 效能 >側邊欄上的問題清單。然後按一下平均值 以平均回應時間降序對問題進行排序。

Find and Fix N ueries in Django Using AppSignal

點擊最慢的端點(books/)查看其詳細資訊。

Find and Fix N ueries in Django Using AppSignal

查看最新範例,我們可以看到該端點在 1090 毫秒內回傳回應。群組細分顯示 SQLite 需要 651 毫秒,而 Django 需要 439 毫秒。

這表示有問題,因為像這樣簡單的端點不應該花費那麼長的時間。

要獲取有關所發生事件的更多詳細信息,請選擇側邊欄中的範例,然後選擇最新範例。

Find and Fix N ueries in Django Using AppSignal

向下捲動到事件時間軸以查看執行了哪些 SQL 查詢。

Find and Fix N ueries in Django Using AppSignal

將滑鼠停留在 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
登入後複製
登入後複製
登入後複製

等待開發伺服器重新啟動並重新測試受影響的端點。

Find and Fix N ueries in Django Using AppSignal

再次進行基準測試後,回應時間從 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 應用程式儀表板,這次由管理員過濾問題:

Find and Fix N ueries in Django Using AppSignal

就我而言,兩個最慢的端點是:

  1. /管理/登入
  2. /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中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板