我有一个这样的模型:
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,我不知道......
答案 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(),看看它是否更快!