Django关联3个模型时如何用select_related/prefetch_related减少冗余查询
问题分析
冗余查询产生的原因:你当前仅通过select_related('kpi_id')关联了Kpis表,而Kpis模型关联的Domains表数据没有被预加载,每次访问t_k.kpi_id.domain_id.display_name时,Django都会对每个未缓存的domain_id发起一次单独的SQL查询,你观察到的10次额外查询就对应10个不同的domain_id记录。
你之前链式调用关联方法失败,大概率是没有指定正确的跨表关联路径,domain_id是Kpis模型的字段,不是TestsAndKpis的直接字段,不能单独作为关联参数传入。
解决方案
直接在select_related中通过双下划线__指定跨表关联路径,一次性关联Kpis和Domains两个关联表,通过一次JOIN查询拉取所有需要的数据,即可完全避免额外的N+1查询问题:
items = [ { 'kpi_type': t_k.type, 'kpi_name': t_k.kpi_id.name, 'kpi_display_name': t_k.kpi_id.display_name, 'domain_display_name': t_k.kpi_id.domain_id.display_name } for t_k in TestsAndKpis.objects.filter(test_id=test_id).select_related('kpi_id__domain_id') ]
额外优化建议
如果你只需要上述几个返回字段,还可以用values()直接构造字典,省略ORM对象实例化的开销,性能会进一步提升:
from django.db.models import F items = list(TestsAndKpis.objects.filter(test_id=test_id).values( kpi_type=F('type'), kpi_name=F('kpi_id__name'), kpi_display_name=F('kpi_id__display_name'), domain_display_name=F('kpi_id__domain_id__display_name') ))
内容的提问来源于stack exchange,提问作者shayms8
相关产品推荐
相关产品推荐

