Debug Toolbar 是发现 N+1 和重复查询最快的办法:把它装在开发环境,页面右边的 SQL 面板会列出每条查询、耗时、调用栈,并标出相似与重复的查询。这篇用 django.test.Client 请求一个真实带工具栏的页面,取出 SQL 面板的内容,再量一下它自己的开销。
响应状态 200 响应里有工具栏(djDebug)吗: True request_id 形如: b7d73367… (每个请求一个,面板内容存在服务端,前端按它取) SQL 面板摘要: default 1.77 ms (101 queries including 100 similar and 100 duplicates ) 提示行: ['100 similar queries. Duplicated 10 times.', '100 similar queries. Duplicated 10 times.'] 面板里带调用栈(能看到是哪一行代码发的查询)——出现 views.py 行: True 出现 site-packages 行: True
工具栏中间件在响应里注入一段脚本和 data-request-id,面板本身的内容存在服务端,浏览器按 request_id 再发请求(这里请求 /__debug__/render_panel/ 取 SQL 面板)。实验里设置了 INTERNAL_IPS = ["127.0.0.1"] 和 DEBUG = True;不满足这两个条件时的表现本文没有测。
修复后 SQL 面板摘要: default 0.05 ms (1 query )
同样的页面用 select_related 后只有一次查询。
SQL 面板摘要: default 0.10 ms (3 queries including 3 similar and 3 duplicates ) 提示: ['3 similar queries. Duplicated 3 times.', '3 similar queries. Duplicated 3 times.', '3 similar queries. Duplicated 3 times.']
N+1 是「相似」的一类;还有一类是完全相同的查询被重复执行。面板都会标出来,并给出 Duplicated 的次数。
没有工具栏 10.31 ms 有工具栏 22.24 ms
它要记录每条查询、抓调用栈,所以请求会明显变慢。对比耗时应当在关掉工具栏的情况下量,不要拿带工具栏的数字当性能结论。