ORM N+1 查詢怎麼解決提示詞(Django ORM、SQLAlchemy、Prisma、JPA / Hibernate 的預加載寫法與檢測方法)

列表接口數據一多就變慢、數據庫日誌裏同樣的查詢出現幾十上百次時用:把 ORM 代碼和查詢日誌給 AI,它定位觸發 N+1 的位置,用對應 ORM 的預加載方式改寫,說明連接查詢與分批查詢的取捨,並給出在測試中自動檢測查詢次數的方法。

NNathaniel bigo··原創首發·AI 輔助撰寫
通用大模型 對話模型通用
你是一名熟悉各種 ORM 性能問題的後端工程師。請幫我排查並修復 N+1 查詢問題。

- ORM 與版本:[ORM 與版本](例:Django 5、SQLAlchemy 2.0、Prisma、Spring Data JPA)
- 數據模型(相關的模型定義和關聯關係):
  [粘貼模型定義]
- 有問題的代碼(接口或序列化代碼):
  [粘貼代碼]
- 查詢日誌(如果有,貼出重複出現的查詢):
  [粘貼查詢日誌]
- 數據規模:[數據規模](例:一頁 50 條,每條關聯 3 張表)

請完成:
1. 定位:指出在哪一行、訪問哪個關聯屬性時觸發了額外查詢,估算一次請求的查詢總數(例如 1 + 50 + 50 × 3)。注意隱藏在序列化器、模板、屬性方法中的關聯訪問。
2. 修復:用該 ORM 的預加載方式改寫,並說明選擇依據:
   - 一對一、多對一:通常用連接查詢一次取回;
   - 一對多、多對多:通常用額外的「按編號批量查詢」,避免連接查詢導致行數膨脹和分頁錯誤;
   - 只需要關聯表的少數字段或統計數時,直接查詢所需字段或用聚合,而不是加載整個關聯對象。
3. 修復後的查詢次數,以及生成的 SQL 大致形式。
4. 副作用:預加載過多不需要的數據導致內存增加;連接查詢與分頁一起使用時的問題;該 ORM 中惰性加載的預設行為。
5. 防止迴歸:在測試中斷言某個接口的查詢次數上限(給出該 ORM 或測試框架中的具體寫法);開發環境中開啟查詢日誌或檢測工具。

修改盡量局部,不改變接口的返回結構。

高亮處換成你自己的內容:[ORM 與版本]、[粘貼模型定義]、[粘貼代碼]、[粘貼查詢日誌]、[數據規模]

ChatGPT Plus 充值

已被複製 0 次

使用說明

怎麼填變量:[數據模型] 要包含關聯關係的定義(外鍵、一對多、多對多),AI 才能判斷用哪種預加載方式。[有問題的代碼] 記得包括序列化或渲染部分,N+1 經常不在查詢代碼裏,而是在把對象轉換成返回數據時訪問了關聯屬性。

常見坑:

  • 查詢代碼看起來只有一條,問題出在序列化器裏逐條訪問關聯對象,每訪問一次就發一條查詢。
  • 對一對多關係也用連接查詢,結果行數成倍增加,分頁時每頁條數不對,內存也上去了。
  • 修好之後沒有測試保護,幾個月後有人在序列化器裏加了一個字段,問題又回來了。

追問技巧:追問「這個列表接口還能怎麼優化:只查需要的字段、加索引、加緩存,分別能提升多少」。

示例輸出

示例,僅供參考(Django)

定位:OrderSerializer 中的 user_name(訪問 order.user.name)和 items(訪問 order.items.all()),一頁 50 條時共 1 + 50 + 50 = 101 次查詢。

python
orders = (
    Order.objects
    .filter(status="PAID")
    .select_related("user")          # 多對一:連接查詢一次取回用戶
    .prefetch_related("items")       # 一對多:額外一次按訂單編號批量查詢明細
    .order_by("-created_at")[:50]
)

修復後共 2 次查詢。

python
from django.test import TestCase

class OrderListQueryTest(TestCase):
    def test_query_count(self):
        make_orders(50)
        with self.assertNumQueries(3):    # 會話 / 鑑權等固定查詢按實際情況調整
            self.client.get("/api/orders/")

同款作品

用這條提示詞做出來的作品;原作者會因此獲得積分

做同款

還沒有同款,來做第一個。

Nathaniel 的更多內容

同主題

同模型

0 條評論

登入 後參與評論

還沒有評論,來搶沙發~