计算平均值时性能不佳

Posted

技术标签:

【中文标题】计算平均值时性能不佳【英文标题】:Poor performance when calculating averages 【发布时间】:2017-07-19 01:27:16 【问题描述】:

我需要显示报价的平均值。问题是我必须计算多对多字段组合的平均值。我还得翻页。

我已经做到了。问题是它的性能很差,我正在寻找解决方法。

模型如下所示:

class Offer(models.Model):
    price = DecimalField(max_digits=10, decimal_places=2)
    quantity = PositiveIntegerField()
    product = ForeignKey(Product)
    qualifiers = ManyToManyField(Qualifier)

计算平均值的相关代码如下:

def get_average(product, qualifiers, users=None):
    offers = Offer.objects.filter(product=product)

    if users is not None:
        offers = offers.filter(user__in=users)

    for qualifier in qualifiers:
        offers = offers.filter(qualifiers=qualifier)

    if not offers.count():
        return None

    offers = offers.aggregate(
        quantity_x_price_sum=Sum(F('quantity') * F('price'), output_field=FloatField()),
        quantity_total=Sum('quantity')
    )

    # Weighted average
    return offers['quantity_x_price_sum'] / offers['quantity_total']


def get_averages(product, limit=20, users=None):
    averages = []

    colors = product.qualifiers.filter(type=1)
    sizes = product.qualifiers.filter(type=2)
    other = product.qualifiers.filter(type=3)

    qualifiers = [colors, sizes, other]
    combinations = itertools.product(*qualifiers)

    for combination in combinations:
        average = get_average(product, combination, users)
        if average is not None:
            averages.append(average)

            if len(averages) == limit:
                return averages

    return averages

主要问题在于 itertools.product(*qualifiers)。这可以产生数百种组合。 在 len(prices) == limit 之前,它必须遍历它们中的每一个并执行查询。

欢迎任何帮助。谢谢。

【问题讨论】:

乍一看,您正在创建一个列表 `combinations = list(itertools.product(*qualifiers))` 来获取您的组合,然后将其传递到 for 循环中。对此的改进是创建一个生成器`combinations = itertools.product(*qualifiers)`,然后您可以将组合传递到for循环中。这将减少生成列表然后对其进行迭代的开销。 【参考方案1】:

您为什么不自己对查询进行平均聚合?

来自 Django 文档:

# Average price across all books.
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
'price__avg': 34.35

https://docs.djangoproject.com/en/1.11/topics/db/aggregation/

编辑:有更复杂的查询方法,希望这会有所帮助。不确定它如何处理非数字数据。

【讨论】:

要添加到这个答案,你应该 - 作为第一步 - 尽可能多地使用 ORM。仅当您无法在 ORM 中完成时,才将所有内容都拉入 Python。这并不总是适用,但它适用于大多数更大/中间的问题。 我需要加权平均值,这与平均值不同 (en.wikipedia.org/wiki/Weighted_arithmetic_mean)。这就是为什么我把这个汇总,做计算。而且我无法直接计算所有报价,我必须为每种产品的每种限定符组合进行计算(然后分页)。我认为这是主要问题。谢谢。

以上是关于计算平均值时性能不佳的主要内容,如果未能解决你的问题,请参考以下文章

计算多组数据的平均值(性能问题)

计算循环内的平均值会降低性能

如何检索“平均值”性能计数器?

提高计算 MS-Access 中大型数据集 7 天滚动平均值的查询的性能

计算平均值时的意外返回值?

计算平均值而不添加负等级退出循环[关闭]