Django中prefetch_related未减少查询量的问题及优化方案
问题原因
你用了prefetch_related('m2m_model_set')但还是触发大量查询,核心原因是:values_list()会生成全新的QuerySet,Django不会复用预取的对象集合,而是每次循环都重新向数据库发起查询。也就是说,你预取的是完整的m2m_model对象,但调用all().values_list('field')时,Django会把这个操作当成独立查询,导致N+1查询问题(1次查MyModel,N次查每个MyModel对应的m2m_model)。
优化方案
方案1:复用预取对象,避免新查询
既然已经预取了完整的m2m_model对象,直接从对象里提取字段就行,不用调用values_list():
myList = [] qs = MyModel.objects.all().prefetch_related('m2m_model_set') for model in qs: # 直接从预取的对象中取field值,不触发新查询 k = [obj.field for obj in model.m2m_model_set.all()] myList.extend(k)
方案2:用Prefetch指定只预取需要的字段
如果不想加载完整的m2m_model对象,可以用Prefetch配合only(),只预取需要的field字段,减少内存占用同时避免额外查询:
from django.db.models import Prefetch myList = [] # 只预取m2m_model的field字段 prefetch = Prefetch('m2m_model_set', queryset=M2MModel.objects.only('field')) qs = MyModel.objects.all().prefetch_related(prefetch) for model in qs: k = [obj.field for obj in model.m2m_model_set.all()] myList.extend(k)
方案3:直接从关联模型反向查询,一次搞定
如果不需要MyModel的其他数据,直接从m2m_model模型出发,通过反向关联过滤,一次查询就能拿到所有需要的field值:
# 假设M2MModel是你的多对多模型,my_model是关联MyModel的外键字段(自动生成或自定义的) myList = list(M2MModel.objects.filter(my_model__isnull=False).values_list('field', flat=True))
这里flat=True会让values_list返回一维列表,连循环都省了。
内容的提问来源于stack exchange,提问作者Kodeeo
相关产品推荐
相关产品推荐

