直接看 sql 比猜快十倍,django 查询慢八成因未看清生成语句;用 explain() 查执行计划最真实,需在 queryset 执行前调用,可识别索引是否命中、全表扫描等问题。

直接看 SQL,比猜快十倍。Django 查询慢,八成是没看清自己生成了什么语句。
用 explain() 查看 QuerySet 对应的执行计划
这是最接近数据库真实行为的方式,不依赖日志或工具栏,直接暴露索引是否命中、是否全表扫描、是否用到排序缓冲区等关键信息。
-
explain()返回的是数据库原生的执行计划文本(如 PostgreSQL 的EXPLAIN ANALYZE,MySQL 的EXPLAIN FORMAT=TRADITIONAL),不是 Django 模拟的伪 SQL - 必须在 QuerySet 执行前调用,例如:
Book.objects.filter(author__name__icontains='leo').explain(),不能对已求值的 QuerySet(如 list() 后)再调用 - 如果看到
Seq Scan(PostgreSQL)或Type: ALL(MySQL),基本说明缺少有效索引;看到Index Scan或Type: ref才算走对路 - 注意
explain(verbose=True)在 PostgreSQL 中会显示实际字段输出,有助于判断是否 SELECT * 拖累了性能
用 str(queryset.query) 看生成的 SQL,但别全信
它只展示“Django 认为要发什么 SQL”,不反映数据库最终怎么执行——比如忽略索引失效、隐式类型转换、函数索引未被识别等问题。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 适合快速检查 JOIN 是否多余、WHERE 条件拼写是否正确、
select_related是否真的转成了 LEFT JOIN - 对
prefetch_related无效:它生成的是多条独立查询,queryset.query只显示第一条(即主表查询) - 带
order_by()但字段无索引时,SQL 看着没问题,执行却极慢——这时必须配合explain()或django-debug-toolbar - 避免在生产环境大量使用,因为字符串化过程本身有开销,且可能暴露敏感字段名
用 django-debug-toolbar 抓住真实请求中的全部查询
它不是替代 explain(),而是补全上下文:哪条查询在哪个视图里触发、耗时多少、是否重复、有没有 N+1。
- 安装后默认开启 SQL 面板,点击每条语句可展开查看完整 SQL + 参数 + 耗时 + 调用栈(精确到某行 views.py)
- 重点看 “Duplicates” 列:同一 SQL 出现多次,大概率是模板中循环调用
obj.foreign_key.field导致 N+1 - 注意 “Time” 和 “Hits” 的比例:单条查询耗时不高,但出现几百次,总延迟照样卡顿
- 禁用缓存后再测,否则可能漏掉本该优化的慢查询(缓存掩盖了问题,但没解决根源)
批量操作时,in_bulk() 和 values_list(..., flat=True) 是真省资源
它们绕过 ORM 实例化开销,直接返回字典或列表,尤其适合 ID 查找、状态校验、异步任务参数准备等场景。
-
Book.objects.in_bulk([101, 205, 307], field_name='id')返回{101: <book>, 205: <book>, ...}</book></book>,比三次get(id=x)少 2 次网络往返和对象构造 -
Author.objects.values_list('id', flat=True).filter(active=True)返回[1, 5, 9, ...],内存占用远低于list(Author.objects.filter(...)) - 慎用
iterator():它减少内存,但会关闭查询缓存,且无法再次遍历;若需多次使用结果,先转成 list 更稳妥 - 不要为了“看起来高效”而滥用
values():如果后续还要访问外键属性(如book.author.name),反而触发额外查询——此时应改用select_related()
真正卡顿的地方,往往藏在你没打开 explain() 的那一次查询里。别靠经验猜索引该加在哪,让数据库自己告诉你。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










