开发环境开启sql日志需在settings.py中配置logging,确保'django.db.backends'的level为debug且handlers包含'console';仅设level不配handlers将无输出。

如何在Django开发环境开启SQL日志输出
直接看到慢SQL的前提是让Django把执行的SQL语句打出来。开发环境下最简单的方式是配置 LOGGING,把 django.db.backends 的日志级别设为 DEBUG。注意不是所有日志后端都默认捕获它——必须显式指定 handler 和 level。
常见错误是只改了 LOGGING['loggers']['django.db.backends']['level'] 却漏掉 'handlers' 配置,导致日志根本没输出;或者误设成 INFO,而 SQL 只在 DEBUG 级别才打印。
- 在
settings.py中确保DEBUG = True - 添加或修改
LOGGING字典,包含'django.db.backends': {'handlers': ['console'], 'level': 'DEBUG'} - 如果用
logging.basicConfig()手动配置过日志,会覆盖 Django 默认配置,需统一管理
Django Debug Toolbar 能否定位慢SQL
可以,但默认不标出“慢”的阈值。django-debug-toolbar 的 SQL 面板会列出所有查询、耗时、是否重复、是否缺少索引提示,但它不会自动高亮超过 100ms 的语句——得自己看时间列。
容易被忽略的是:它只对 HTML 响应生效(即中间件拦截响应体),API 接口(如返回 JSON)默认不触发面板;另外,如果视图用了 @csrf_exempt 或绕过中间件(如异步视图、management command),Toolbar 完全不工作。
- 安装后确认
MIDDLEWARE中包含'debug_toolbar.middleware.DebugToolbarMiddleware' - 检查
INTERNAL_IPS是否包含当前请求 IP(本地开发通常设为['127.0.0.1']) - 想监控 API,可临时在视图里加
from debug_toolbar.panels.sql import SQLPanel; SQLPanel().process_request(request),但仅限调试
如何用 django-silk 或自定义中间件抓取耗时SQL
django-silk 是少数能按执行时间排序、支持过滤和采样的工具,比 Debug Toolbar 更适合找慢 SQL。但它需要独立数据库表存储记录,上线前务必关掉——否则写入开销明显。
提供使用 django-unfold (v0.56+) 构建高级 Django 管理界面的专业指导。当用户提及 django-unfold、unfold admin 等内容时使用此技能。
更轻量的做法是写个简易中间件,在 process_response 里遍历 connection.queries,筛选出耗时 >50ms 的语句并打日志。注意:这个列表只在 DEBUG=True 时有内容,且每次请求后清空;若视图里调用了 reset_queries(),会提前清空。
-
django-silk安装后需运行python manage.py migrate silk,否则报错no such table: silk_response - 自定义中间件中别直接 print,要用
logging.getLogger(__name__),避免干扰测试断言 - 耗时判断用
float(q['time']) > 0.05(单位是秒),别用字符串比较
为什么 EXPLAIN 分析后发现没走索引,但 shell 里却走了
最常见原因是查询条件里的字段类型不匹配。比如数据库字段是 UUIDField,但代码里传入的是字符串 'abc123' 而非 uuid.UUID('abc123'),PostgreSQL 会隐式转换,导致索引失效;MySQL 对字符串前导空格或大小写的隐式转换也有类似问题。
另一个隐蔽点是 Django 的 select_related / prefetch_related 在复杂嵌套下可能生成冗余 JOIN,EXPLAIN 显示 rows 很大,但实际慢的未必是这条 SQL——可能是它触发了后续几十次 N+1 查询。得结合 connection.queries 时间戳顺序交叉验证。
- 用
str(queryset.query)看最终生成的 SQL,再贴到psql或mysql里手动EXPLAIN ANALYZE - 检查字段定义和传参类型是否严格一致,尤其
CharFieldvsTextField、IntegerFieldvsBigIntegerField - 在 shell 里复现时,确保用的是同一数据库连接(
using='default'),避免读到了从库缓存
真正卡住的地方往往不在 SQL 本身,而在 ORM 层的懒加载链、信号触发、或事务隔离级别导致的锁等待——这些都不会出现在 connection.queries 里。先确认慢的是不是 SQL,再决定要不要深入数据库层面。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










