我正在尝试优化 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)
我有一个函数可以获取所有Label
s 和Thing
s 并将它们放入 JSON 数据结构中,其中s 使用它们的 s (主键)Thing
引用s 。像这样的东西:Label
id
{
'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。有没有办法只预取id
s 的Label
s ?我试过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。Thing
Thing
Label
概括:
Label
并由Thing
a 连接ManyToManyField
。无论如何,我正在获取所有 Label
s 和Thing
s 。那么我如何有效地获取他们的多对多关系呢?