如何使此查询集更可容忍?

时间:2018-07-05 10:21:51

标签: django django-models

我有以下课程:

class Instance(models.Model):
    products = models.ManyToManyField(Product, blank=True)


class Product(models.Model):
    description = HTMLField(blank=True, null=True)
    short_description = HTMLField(blank=True, null=True)

这是我用来更新实例的表格

class InstanceModelForm(InstanceValidatorMixin, UpdateInstanceLastUpdatedMixin, forms.ModelForm):
    class Meta:
        model = Instance
    products = forms.ModelMultipleChoiceField(required=False, queryset=Product.objects.annotate(i_count=Count('instance')).order_by('i_count'))

我的instance-product表相当大(〜1000行),并且自从我添加了产品的查询集以来,我看到由于heroku的30秒请求限制而导致Web请求超时。

我的目标是对该查询集执行某些操作,以使用户不再超时。

我有以下见解:

  1. 精度对我而言并不重要-不一定必须非常准确。是的,我想按产品链接到的实例数对产品进行排序,但是如果偏离5或10,则没关系 那么多。

  2. 有限数量的产品-当我的用户选择要链接到实例的产品时,他们主要对与实例的总链接少于10个的产品感兴趣。我不知道部分查询是否准确,但是如果可能的话,我愿意尝试。

  3. 工作量-我知道可以安装一些框架​​来缓存很多东西。我正在寻找重量轻且需要不到1个小时才能启动并运行的东西。

1 个答案:

答案 0 :(得分:1)

首先,我想确保性能问题实际上来自查询。我试图重现您的问题:

>>> Instance.objects.count()
102499
>>> Product.objects.count()
1000
>>> sum(p.instance_set.count() for p in Product.objects.all())/Product.objects.count()
273.084
>>> list(Product.objects.annotate(i_count=Count('instance')).order_by('i_count'))
[...]
>>> from django.db import connection
>>> connection.queries[-1]
{'sql': 'SELECT "products_product"."id", "products_product"."description", "products_product"."short_description", COUNT("products_instance_products"."instance_id") AS "i_count" FROM "products_product" LEFT OUTER JOIN "products_instance_products" ON ("products_product"."id" = "products_instance_products"."product_id") GROUP BY "products_product"."id", "products_product"."description", "products_product"."short_description" ORDER BY "i_count" ASC', 'time': '0.189'}

偶然地,我创建了一个可能比您大得多的数据集。如您所见,我有1000个产品,平均约有273个相关实例,但是查询仍然不到一秒钟(在SQLite和PostgreSQL上)。

heroku run bash使用一次性测功机,并检查是否获得相同的数字。

我的猜测是您的性能问题是由

引起的
  • n + 1个查询,其中,每个Product都会进行一个额外的查询,例如在您的Product.__str__方法中。
  • MultipleChoiceField字段的实际呈现。默认情况下,它将呈现为<select>,每个<option>的{​​{1}}。这可能很慢,即使不是那样,使用起来也很不方便。您可能想要使用其他小部件,例如Product