我正在尝试优化 Django 应用程序的数据库查询。这是一个简化的示例:
class Label(models.Model):
name = models.CharField(max_length=200)
# ... many other fields ...
class Thing(models.Model):
name = models.CharField(max_length=200)
labels = models.ManyToManyField(Label)
我有一个函数可以获取所有Labels 和Things 并将它们放入 JSON 数据结构中,其中s 使用它们的 s (主键)Thing引用s 。像这样的东西:Labelid
{
'labels': [
{ 'id': 123, 'name': 'label foo' },
...
],
'things': [
{ 'id': 45, 'name': 'thing bar', 'labels': [ 123, ... ] },
...
]
}
使用 Django 获取这种数据结构的最有效方法是什么?假设我有L Label s 和T Thing s,平均值Thing有x Label s。
方法一:
data = {}
data['labels'] = [model_to_dict(label) for label in Label.objects.all()]
data['things'] = [model_to_dict(thing) for thing in Thing.objects.all()]
这使得 (1 + 1 + T ) 数据库查询,因为model_to_dict(thing)需要Label为每个Thing单独获取 s。
方法二:
data = {}
data['labels'] = [model_to_dict(label) for label in Label.objects.all()]
data['things'] = [model_to_dict(thing) for thing in
Thing.objects.prefetch_related('labels').all()]
这只会进行 (1 + 1 + 1) 次数据库查询,因为获取的s 现在在单个附加查询中预取了Thing它们的 s。Label
这仍然不能令人满意。 prefetch_related('labels')将获取相同的许多副本Label,而我只需要它们id的 s。有没有办法只预取ids 的Labels ?我试过prefetch_related('labels__id')了,但没有用。我还担心因为T很大(数百个),prefetch_related('labels')导致 SQL 查询带有很大的IN子句。L要小得多(< 10),所以我可以这样做:
方法三:
data = {}
data['labels'] = [model_to_dict(label) for label in
Label.objects.prefetch_related('thing_set').all()]
things = list(Thing.objects.all())
# plug in label ids by hand, and also fetch things that have zero labels
# somehow
这会产生一个较小的IN子句,但仍然不能令人满意,因为如果 a有多个s,则会prefetch_related('thing_set')获取重复的s。ThingThingLabel
概括:
Label并由Thinga 连接ManyToManyField。无论如何,我正在获取所有 Labels 和Things 。那么我如何有效地获取他们的多对多关系呢?