改进Django Slice Step Performance

时间:2016-12-01 05:38:54

标签: django postgresql django-models

我有一个应用程序,我使用Django实例来存储来自多个独立实体的日志。然后,我有一个UX组件,它从django实例中获取日志文件并绘制值。为了保持合理,我尝试只获取日志值的样本,然后在用户放大时增加粒度。 我的问题是随着日志数量的增加,抓取每个下采样日志组的时间越来越不可持续。

以下是模型的简化版本

class LogModel(models.Model):
   localtime = models.DateTimeField(db_index=True)
   value1 = models.FloatField(blank=True, null=True)
   value1 = models.FloatField(blank=True, null=True)
   value1 = models.FloatField(blank=True, null=True)
   owner = models.ForeignKey('auth.User', related_name='logs')

以下是我用来获取数据的示例查询:

q = LogModel.objects.filter(owner=SomeOwner).order_by('localtime')
qNum = q.count()
logs = q[:qNum:(qNum/1000)]

有时运行此查询需要很长时间(~16s)。现在大型设备中的日志数量约为150K。如果有其他东西击中数据库,可能需要很长时间(> 1分钟)。

其他信息: 系统: VM带2个CPU,4GB RAM DB:PostgreSQL 9.3 操作系统:Ubuntu 14.04

我试图遵循一般优化数据库指南,但运气不佳。

我尝试过的事情: 增加了ram到数据库。 限制并发繁重数据库查询的数量(3)。

总数据库不是很大,应该绝对适合我分配给数据库的1GB。我觉得我错过了一些非常基本的理解,它是如何工作的,或者是一个基本的优化。 谢谢,

1 个答案:

答案 0 :(得分:1)

最初,我认为你遇到了postgresql slow count problem的变体,因为我误读了切片从队列的尾部拿走了1000个项目。由于两个原因,这本身会很慢;首先是已经提到的慢postgresql计数,其次使用大偏移导致服务器对所有数据进行排序,然后跳到该偏移量。但你正在采取的切片实际上更糟糕!!

qNum = q.count()
logs = q[:qNum:(qNum/1000)]

您告诉ORM计算行数(慢),然后从中获取每个nth行。不幸的是,SQL语言并没有内置对“步骤”的支持。参数LIMIT and OFFSET

切片django queryset以获取每个nth项实际上是在内存中使用django而不是在RDBMS级别完成的。 Django遍历整个查询集,将每个第n项复制到列表并返回列表。所以毫不奇怪,它很慢。索引是无用的,因为你强迫整个表被读取。

我建议使用F expression对主键应用模运算(您可以在postgresql中为其创建partial index)。

LogModel.objects.annotate(idmod4=F('id') % 10).filter(idmod4=0)