使用350000+ regs和复杂查询提高Django性能

时间:2011-08-30 17:44:18

标签: django performance

我有一个这样的模型:

class Stock(models.Model):
    product = models.ForeignKey(Product)
    place = models.ForeignKey(Place)
    date = models.DateField()
    quantity = models.IntegerField()

我需要为每个date的{​​{1}}获取最新的quantity} product, 数据库中有近500种产品,100种产品和350000种库存记录。

我目前的代码是这样的,它可以用于测试,但实际数据需要很长时间,这是无用的

place

你怎么能让它更快?

修改 重写了这段代码:

    stocks = Stock.objects.filter(product__in=self.products,
                                  place__in=self.places, date__lt=date_at)
    stock_values = {}
    for prod in self.products:
        for place in self.places:
            key = u'%s%s' % (prod.id, place.id)
            stock = stocks.filter(product=prod, place=place, date=date_at)
            if len(stock) > 0:
                stock_values[key] = stock[0].quantity
            else:
                try:
                    stock = stocks.filter(product=prod, place=place).order_by('-date')[0]
                except IndexError:
                    stock_values[key] = 0
                else:
                    stock_values[key] = stock.quantity
    return stock_values

效果更好(从256秒到64)但仍需要改进它。也许是一些自定义SQL,我不知道......

2 个答案:

答案 0 :(得分:2)

Arthur是对的,len(stock)不是最有效的方式。你可以在内循环中更进一步“更容易请求宽恕而非许可”的路线:

key = u'%s%s' % (prod.id, place.id)
try:
    stock = stocks.filter(product=prod, place=place, date=date_at)[0]
    quantity = stock.quantity
except IndexError:
    try:
        stock = stocks.filter(product=prod, place=place).order_by('-date')[0]
        quantity = stock.quantity
    except IndexError:
        quantity = 0
stock_values[key] = quantity

我不确定与仅更改长度检查相比会有多大改善,但我认为至少应该将其限制为两个LIMIT 1的查询(请参阅Limiting QuerySets

请注意,这仍然会执行大量的数据库命中,因为您可以运行该循环近50000次。优化你的循环方式,你仍处于更好的位置。

答案 1 :(得分:0)

也许诀窍在于len()方法!

按照文档from

  

注意:如果您要做的就是确定,请不要在QuerySets上使用len()   集合中的记录数。处理一个更有效的方法   使用SQL的SELECT COUNT(*)和Django计算数据库级别   正是出于这个原因提供了count()方法。见count()   下方。

所以尝试将len更改为count(),看看它是否更快!