【问题标题】:How do I optimize the SQL for this Django view?如何优化此 Django 视图的 SQL?
【发布时间】:2016-02-23 05:14:52
【问题描述】:

我正在编写一个 Django 视图,该视图从数据库中查询对象列表以及来自相关字段的一些信息。问题是数据库对 7 个对象执行 10 次查询。代码如下:

模板代码:

{% for resource in results %}
    <li>
        <a href="{{resource.url}}"> {{resource.url}}
                 {{resource.stats_set.values.0.avg}}</a>
<!-- truncated, the rest of the template just generates a form and 
 isn't causing any unnecessary sql -->
{% endfor %}

查看代码:

class ResourceList(generic.ListView):
    model = Submissions
    context_object_name = 'results'
    template_name = 'url_list.html'

以及必要的模型:

class Submissions(models.Model):
    LEVEL = (
        ('Introductory', 'Introductory'),
        ('Intermediate', 'Intermediate'),
        ('Academic', 'Academic'),
    )

    MEDIA_TYPE = (
        ('HTML', 'HTML'),
        ('PDF', 'PDF'),
        ('Video', 'Video'),
        ('Other', 'Other'),
    )
    id = models.AutoField(primary_key=True)
    url = models.URLField(unique=True)
    tags = models.ForeignKey(MajorTags, default=0)
    level = models.CharField(choices=LEVEL, max_length=25)
    media_type = models.CharField(choices=MEDIA_TYPE, max_length=25)

    def __unicode__(self):
        return self.url

    def __str__(self):
        return self.url

class Stats(models.Model):
    url = models.ForeignKey(Submissions)
    id = models.AutoField(primary_key=True)
    avg = models.FloatField(default=0)
    std_dev = models.FloatField(default=0)

    def __unicode__(self):
        return self.url.url + " " + str(self.avg)

    def __str__(self):
        return self.url.url + " " + str(self.avg)

问题的根源在于{{resource.stats_set.values.0.avg}} 位。问题是,如果我尝试执行queryset = Submissions.objects.all().select_related('avg'),我会收到一条错误消息,指出select_related() 的唯一选项是tags,这是有道理的,因为这是Submissions 模型中唯一具有外键的字段。我的数据库结构此时已很好地锁定,所以我无法更改数据库。我也无法查询Stats并从那里进行反向操作,因为我需要获取还没有统计信息的数据。

如何减少正在运行的 SQL 查询的数量?

【问题讨论】:

    标签: python sql django query-optimization


    【解决方案1】:

    您应该使用prefetch_related,它用于对反向外键或多对多关系进行高效查询:

    来自文档:

    prefetch_related()

    返回一个将自动检索的 QuerySet,在单个 每个指定查找的批处理相关对象。

    def get_queryset(self,*args,**kwargs):
         return Submissions.objects.all().prefetch_related('stats_set')
    

    这将需要一个额外的查询,但其想法是一次获取所有相关信息,而不是每个Submissions 对象一次。

    附带说明,建议对模型类名称使用名词的单数Submission 而不是Submissions

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-25
      • 2023-03-17
      • 2012-05-31
      • 2021-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多