TLDR:如何防止生成的 SQL 查询中出现非常大的 IN 集?
当我从模型对象中预获取指向模型标签的 ManyToMany 字段时:
obj_qs = models.Object.objects.filter(created_time__gt = 2024)
obj_qs.prefetch_related('tags')
我得到以下形式的预取 SQL 查询:
SELECT (`main_object_tag`.`object_id`) AS `_prefetch_related_val_object_id`, `main_tag`.`id`, `main_tag`.`name` FROM `main_tag` INNER JOIN `main_object_tag` ON (`main_tag`.`id` = `main_object_tag`.`tag_id`) WHERE `main_object_tag`.`object_id` IN (1, 2, 3, 4, 5); args=(1, 2, 3, 4, 5)
问题是,这样 IN 子句可能会很大——在我的例子中,有数十万个对象。我可以以某种方式解决这个问题 - 使用查询而不是“IN”规范吗?
补充:为什么?
随后我们将通过以下方式序列化对象:
return JsonResponse([
{
'name': obj.name,
'tags': [tag.name for tag in obj.tags.all()]
} for obj in obj_qs
])
如果数量太大,您可以使用 chunks,从而以约 10'000 个元素的块形式获取查询集。
.iterator(..)
为此:
return JsonResponse(
[
{'name': obj.name, 'tags': [tag.name for tag in obj.tags.all()]}
for obj in obj_qs.iterator(10000)
]
)
另一个想法是通过仅从对象和标签获取相关数据来限制传输的数据量,在本例中为
.name
:
from django.db.models import Prefetch
obj_qs = models.Object.objects.filter(created_time__gt=2024).only('name')
obj_qs.prefetch_related(Prefetch('tags', Tag.objects.only('pk', 'name')))