我面临与 django-mptt 相关的戏剧性性能问题。这是我的情况:
- 我有一个测验课
- 我有一个带有 FK 到 Quizz 和一个 FK 到 Category 类的 Question 类
- 我有一个属于 MPTT 树的 Category 类(因为我的分类是分层的)
现在,我有一个包含 7 个问题的实际测验和一个管理视图,该视图将问题显示为 QuizzAdmin 视图的内联,并且内联带有 Category as Select 字段。
然后麻烦来了:
- 我已经将问题加载为 prefetch_related (甚至尝试让 questions__category 像这样加载)
- 尽管如此,我还是看到我的调试工具栏显示了在模板渲染时发生的一系列 16 个查询 (template/edit_inline/tabular.html)。在我的开发笔记本电脑上,这意味着加载这一切需要 1 分钟(在我的带有实际数据的测试环境中,这意味着 10 分钟!)
这 16 个查询是以下的连续查询:(请注意我正在使用虚拟类别进行测试)
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
知道我可以做些什么来减少查询数量吗?
提前谢谢洛杉矶
[编辑 1]
有一个愚蠢的事情解释了问题的一半:我的类别的 __unicode__() 正在查看对象的父母的 __unicode__() (幸运的是我的树只有 2 级深)
现在在我的最佳配置中,对于 8 个条目,我仍然有 9 次“SELECT ... FROM quizz_category”(没有 WHERE 子句),据说是为了构建 Select 字段的选择。
任何人都知道如何缓存这个查询并且只运行一次?
注意:我当前的最佳配置是在 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
以下是调试工具栏对这些查询的说明(都一样):
选择“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) output = [self.widget.render(name, value, *args, **kwargs)] 49
{{ field.contents|换行符}}
50 {% else %} 51
{{ field.field.errors.as_ul }} 52
{{ field.field }} 53
{% endif %} 54
55
{% endfor %} /Library/Python/2.7/site-packages/ django/contrib/admin/templates/admin/edit_inline/tabular.html