django-mptt に関連して劇的なパフォーマンスの問題に直面しています。これが私のケースです:
- クイズ教室があります
- Quizz への FK と Category クラスへの FK を持つ Question クラスがあります。
- MPTT ツリーである Category クラスがあります (分類が階層的であるため)
現在、7 つの質問を含む実際のクイズと、質問を QuizzAdmin ビューにインラインとして表示する管理ビューがあり、インラインには [選択] フィールドとしてカテゴリが表示されます。
次に、問題が発生します。
- 質問を prefetch_related としてロードしました(さらに、questions__category をロードしようとしました)。
- それにもかかわらず、デバッグ ツールバーには、テンプレートのレンダリング時に発生する一連の 16 個のクエリが表示されます (template/edit_inline/tabular.html)。私の開発用ラップトップでは、これをすべてロードするのに 1 分かかります (実際のデータを使用したテスト環境では、10 分を意味します!)
これらの 16 のクエリは、以下の一連のクエリです: (pls は、ダミーのカテゴリでテストしていることに注意してください)
SELECT "quizz_category"."id", "quizz_category"."parent_id", "quizz_category"."name",
"quizz_category"."name_en", "quizz_category"."name_fr", "quizz_category"."lft",
"quizz_category"."rght", "quizz_category"."tree_id", "quizz_category"."level",
"quizz_category"."description", "quizz_category"."description_en",
"quizz_category"."description_fr" FROM "quizz_category" ORDER BY
"quizz_category"."tree_id" ASC, "quizz_category"."lft" ASC
と
SELECT "quizz_category"."id", "quizz_category"."parent_id", "quizz_category"."name",
"quizz_category"."name_en", "quizz_category"."name_fr", "quizz_category"."lft",
"quizz_category"."rght", "quizz_category"."tree_id", "quizz_category"."level",
"quizz_category"."description", "quizz_category"."description_en",
"quizz_category"."description_fr" FROM "quizz_category" WHERE ("quizz_category"."lft" <= 3
AND "quizz_category"."rght" >= 6 AND "quizz_category"."tree_id" = 1 ) ORDER BY
"quizz_category"."lft" ASC
クエリの数を減らすために何ができるか考えていますか?
よろしくお願いします LA
[編集1]
問題の半分を説明する愚かなことがありました: 私のカテゴリの __unicode__() は、オブジェクトの親の __unicode__() を見ていました (幸い、私のツリーは 2 レベルの深さしかありません)
現在、私の最適な構成では、おそらく Select フィールドの選択肢を構築するために、8 つのエントリに対して "SELECT ... FROM quizz_category" (WHERE 句なし) が 9 回あります。
このクエリをキャッシュして一度だけ実行する方法を知っている人はいますか?
注:現在の最適な構成は、 QuestionInline に .select_related('category') を含めることです
class QuestionInline(admin.TabularInline): # admin.StackedInline
model = Question
extra = 0
ordering = ['position',]
def queryset(self, request):
return super(QuestionInline, self).queryset(request).select_related('category')
class QuizzAdmin(admin.ModelAdmin):
list_display = ["name","rating_scale"]
inlines = [QuestionInline]
fieldsets = (
(None, {'fields': (('name'), ('type',), 'description',
'rating_scale' )}),
)
def queryset(self, request):
if getattr(self,'is_change_list', False):
# it's a changelist view, we don't need details on ForeignKey-accessible objects
return super(QuizzAdmin, self).queryset(request)
else:
return super(QuizzAdmin, self).queryset(request).select_related('rating_scale')
def changelist_view(self, request, extra_context=None):
self.is_change_list = True
return super(QuizzAdmin, self).changelist_view(request, extra_context)
class Category(AbstractAnalyticTreeCategory):
description = BusinessTextField(_("description")) # basically a text field of mine
tree = AnalyticTreeManager()
def __unicode__(self):
return self.name
class Quizz(models.Model):
name = models.CharField(_("name of the quizz"), unique=True, max_length=60)
description = BusinessTextField(_("description"))
type = models.CharField(_("type"), choices=QUIZZ_TYPE_CHOICES, default=QUIZZ_SELF_EVALUATION, null=False, blank=False, max_length=2)
rating_scale = models.ForeignKey(MCQScale, verbose_name=_("applicable rating scale"), on_delete=models.PROTECT)
def __unicode__(self):
return self.name
class Question(models.Model):
position = models.IntegerField(verbose_name=_("order index"), help_text=_("Order in which the question will appear."))
quizz = models.ForeignKey(Quizz, verbose_name=_("Related quizz"), null=False, blank=False, related_name='questions')
title = BusinessCharField(_("item"), max_length=60, null=True, blank=True)
text = BusinessTextField(_("question text"),)
category = TreeForeignKey(Category, verbose_name=_("dimension"), null=True, blank=False, on_delete=models.SET_NULL)
def __unicode__(self):
return self.title
これらのクエリについてデバッグ ツールバーに表示される内容は次のとおりです (すべて同じです)。
SELECT "quizz_category"."id", "quizz_category"."parent_id", "quizz_category"."name", "quizz_category"."name_en", "quizz_category"."name_fr", "quizz_category"."lft"," quizz_category"."rght", "quizz_category"."tree_id", "quizz_category"."level", "quizz_category"."description", "quizz_category"."description_en", "quizz_category"."description_fr" FROM "quizz_category" ORDER BY "quizz_category"."tree_id" ASC, "quizz_category"."lft" ASC 3,68816058264% 1,66 Sel Expl 接続: デフォルト 分離レベル: コミットされた読み取り トランザクション ステータス:トランザクションで /Library/Python/2.7/site-packages/django/contrib/staticfiles/handlers.py呼び出し中(72) return self.application(environ, start_response) /Library/Python/2.7/site-packages/django/contrib/admin/widgets.py in render(263) 出力 = [self.widget.render(name, value, *args, **kwargs)] 49
{{ field.contents|改行br }}
50 {% else %} 51
{{ field.field.errors.as_ul }} 52
{{ field.field }} 53
{% endif %} 54
55
{% endfor %} /Library/Python/2.7/site-packages/ジャンゴ/contrib/admin/templates/admin/edit_inline/tabular.html