【问题标题】:Improving Django Slice Step Performance提高 Django 切片步骤的性能
【发布时间】:2016-12-01 05:38:53
【问题描述】:

我有一个应用程序,我在其中使用 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)]

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

其他信息: 系统: 带有 2 个 CPU、4GB 内存的虚拟机 数据库:PostgreSQL 9.3 操作系统:Ubuntu 14.04

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

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

整个数据库不是很大,绝对可以放入我分配给数据库的 1GB 中。我觉得我对它的工作原理或基本优化缺少一些非常基本的理解。 谢谢,

【问题讨论】:

    标签: django postgresql django-models


    【解决方案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)
    

    【讨论】:

    • 这正是我想要的。谢谢你。性能提升 1000 倍。
    • 很高兴能帮上忙。
    • @e4c5 在这种情况下,创建索引的代码是什么样的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-15
    • 2019-08-06
    • 2019-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多