如何在Django中以最佳效率查询?

时间:2019-06-11 11:03:11

标签: django

我最近发现太多SQL查询优化问题。 django-debug-tool报告了数百个相似和重复的查询。因此,我试图找出Django ORM的最佳效率,以避免不必要的Queryset评估。

如下面的商店模型所示,商店模型具有许多外键和ManyToManyFields。由于这种结构,许多代码片段对HTML模板文件(例如store.image_set.allstore.top_keywords.all)产生了很大的影响。一切都以store.开头在每个商店详细信息页面中,我只是传递一个具有prefetch_related或select_related的缓存的商店对象。这是一个不好的方法吗?我应该分别在views.py上分别缓存和prefetch_related或select_related每个外键或ManyToManyField吗?

HTML模板

{% for img in store.image_set.all %}
  {{ img }}
{% endfor %}
{% for top_keyword in store.top_keywords.all %}
  {{ top_keyword }}
{% endfor %}
{% for sub_keyword in store.sub_keywords.all %}
  {{ sub_keyword }}
{% endfor %}

views.py

class StoreDetailView(View):

    def get(self, request, *args, **kwargs):

        cache_name_store = 'store-{0}'.format(store_domainKey)
        store = cache.get(cache_name_store, None)
        if not store:
            # query = get_object_or_404(Store, domainKey=store_domainKey)
            query = Store.objects.all().prefetch_related('image_set').get(domainKey=store_domainKey)
            cache.set(cache_name_store, query)
            store = cache.get(cache_name_store)

        context = {
            'store': store,
        }
        return render(request, template, context)

models.py

class Store(TimeStampedModel):

    categories = models.ManyToManyField(Category, blank=True)
    price_range = models.ManyToManyField(Price, blank=True)

    businessName = models.CharField(unique=True, max_length=40,
                                    verbose_name='Business Name')

    origin = models.ForeignKey(Origin, null=True, on_delete=models.CASCADE, blank=True)
    ship_to = models.ManyToManyField(ShipTo, blank=True)

    top_keywords = models.ManyToManyField(Keyword, blank=True, related_name='store_top_keywords')
    sub_keywords = models.ManyToManyField(SubKeyword, blank=True, related_name='store_sub_keywords')

    sponsored_stores = models.ManyToManyField(
        'self', through='Sponsorship', symmetrical=False, related_name='sponsored_store_of_store')
    similar_stores = models.ManyToManyField(
        'self', through='Similarity', symmetrical=False, related_name='similar_store_of_store')


    shortDesc = models.TextField(blank=True, verbose_name='Short Description')
    longDesc = models.TextField(blank=True, verbose_name='Long Description')

    returnPol = models.TextField(verbose_name='Return Policy', blank=True)
    returnUrl = models.CharField(max_length=255, null=True, blank=True, verbose_name='Return Policy URL')

    likes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, editable=False)

    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE,
                                   related_name='stores_of_created_by', null=True, blank=True)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE,
                                   related_name='stores_of_updated_by', null=True, blank=True)

1 个答案:

答案 0 :(得分:1)

我真的不建议自定义缓存/性能优化,除非这是最后的选择。 Django在querysetsoptimisation上都有出色的文档-如果您遵循这些文档,那么您很少会遇到需要自定义解决方法的主要性能问题。

认为这里的问题是,您要在模板中打印对象,然后调用它们的str()方法。这没有什么问题,但是我将检查您在str()方法中使用的是什么变量。我怀疑您正在引用其他模型?即图像模型(或其他任何模型)中的str()方法正在执行类似image.field.other_field的操作。在这种情况下,您的查询应如下所示:

queryset = Store.objects.prefetch_related('image_set__field')

您的最终查询集可能类似于:

queryset = Store.objects.prefetch_related('image_set__field1', 'image_set__field2', 'top_keywords__field3', ...)

请注意,您仍然可以像这样将其传递给get_object_or_404

get_object_or_404(queryset, pk=<your_stores_id>)

希望这会有所帮助。