2016-12-01 121 views
1

我有一个应用程序,我正在使用Django实例存储来自多个独立实体的日志。然后我有一个UX组件,它从django实例抓取日志文件并绘制这些值。为了保持合理性,我尝试只抓取一个日志值样本,然后在用户放大时增加粒度。 我的问题是,随着日志数量的增加,抓取每个下采样日志组的时间越来越长不可持续的。改善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 W/2 CPU,4GB RAM DB:PostgreSQL的9.3 操作系统:Ubuntu的14.04

我曾试图按照一般的优化数据库的指导方针,但一点运气。

我曾尝试过的事情: 增加了对数据库的内存。 限制并发重型数据库查询的数量(3)。

总数据库不是很大,应该绝对适合我分配给数据库的1GB。我觉得我缺少一些对其工作原理或基本优化的基本理解。 谢谢,

回答

0

最初,我以为你碰到了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) 
+0

这正是我所期待的。谢谢。性能提高1000倍。 –

+0

很高兴得到了帮助。 – e4c5