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(主キー)を使用してsをThing
参照します。このようなもの:Label
id
{
'labels': [
{ 'id': 123, 'name': 'label foo' },
...
],
'things': [
{ 'id': 45, 'name': 'thing bar', 'labels': [ 123, ... ] },
...
]
}
Djangoを使用してそのようなデータ構造を取得する最も効率的な方法は何ですか?LsとTsがあり、 平均がxsであるとします。Label
Thing
Thing
Label
方法1:
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)データベースクエリが作成されます。これは、それぞれのsを個別model_to_dict(thing)
にフェッチする必要があるためです。Label
Thing
方法2:
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)データベースクエリのみが作成されます。Thing
これは、フェッチされたLabel
sが単一の追加クエリでプリフェッチされるようになったためです。
これはまだ満足のいくものではありません。 prefetch_related('labels')
同じの多くのコピーをフェッチしLabel
ますが、必要なのはそれらのコピーだけですid
。id
のLabel
sのみをプリフェッチする方法はありますか?試しprefetch_related('labels__id')
ましたが、うまくいきませんでした。また、 Tが大きい(数百)ため、大きな句prefetch_related('labels')
を含むSQLクエリが生成されることも懸念されます。Lははるかに小さい(<10)ので、代わりにこれを行うことができます。IN
方法3:
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
これにより、句が小さくなりますが、 aに複数のsがある場合、重複するsをフェッチするIN
ため、それでも満足のいくものではありません。prefetch_related('thing_set')
Thing
Thing
Label
概要:
Label
とThing
で接続されていManyToManyField
ます。とにかくすべて Label
のsとsをフェッチしています。Thing
では、どうすれば多対多の関係を効率的に取得できますか?