Django + Postgres + 大型时间序列
我正在考虑一个项目,这个项目涉及大量的时间序列数据,这些数据大部分是无法压缩的。我在想用Django加Postgres配合原始SQL是否合适。
我的时间序列数据大约是每小时2000个对象,每年大约有200万行数据。我希望能做到两件事:1)通过连接提取数据进行分析,2)在网上进行一些基本的概览工作,这些工作由Django提供支持。我觉得最好的办法是用Django来处理这些对象,但在处理大量的时间序列数据时,直接使用原始SQL会更有效。我把这个方法看作是一种混合方式;虽然这可能有些风险,但用完整的ORM(对象关系映射)来处理这么长的数据序列感觉有些过于复杂。有没有更好的方法呢?
4 个回答
你也可以考虑使用PostGIS这个Postgres的扩展,它支持栅格数据类型(简单来说就是一大堆数字组成的网格),并且有很多功能可以帮助你使用这些数据。
不过,在这种情况下不要使用ORM(对象关系映射),你最好直接在服务器上写SQL。因为ORM在处理大规模数字数据时会增加很多额外的负担。而且它在Python中处理大矩阵时也不太合适,处理这些你需要用到numpy。
听起来你想了解一下 timescale。我自己还没用过,但它似乎是PostgreSQL的一个扩展,所以我猜它应该能完全支持Django。而且它能处理的性能非常强大,
可以每秒处理成千上万的行数据和数百万个指标,甚至在单个节点上也能处理到1000亿行数据。
时间序列数据库似乎总是被不断地重新发明,正如上面提到的,关系型数据库并不太适合这个用途。
我做的事情是把Django和InfluxDB结合起来,后者是专门为时间序列数据设计的。使用起来非常棒,而且Python的客户端库可以和pandas数据框配合使用。这意味着你可以使用InfluxDB的查询语言直接对数据进行操作,或者把所有数据(如果需要的话,可以是汇总后的)拉到Python中进行分析。我的应用程序处理的数据流量和你需要的差不多。
我根据需要将InfluxDB的系列名称与Django的应用程序/模型/主键关联起来。时间序列数据存放在关联的InfluxDB系列中,而一些变化缓慢或关系型的数据则存放在Django的ORM字段里。
如果我理解你的意思没错的话,你在考虑把时间序列数据存储在PostgreSQL数据库里,每条时间序列记录占用一行。别这么做。
首先,这个问题是理论上的。关系型数据库(我想大部分数据库都是这样)是基于行独立的原则,而时间序列的记录是有物理顺序的。当然,数据库索引可以为数据库表提供某种顺序,但这个顺序主要是为了加快搜索速度,或者以字母顺序等方式展示结果,并不意味着这个顺序有什么特别的含义。无论你怎么排序,每个客户都是独立的,每个客户的购买记录也是独立的,即使你可以把它们按时间顺序整理成客户的购买历史。时间序列记录之间的相互依赖性要强得多,这使得关系型数据库不太适合存储时间序列。
在实际操作中,这意味着表和它的索引占用的磁盘空间会非常大(可能是存储时间序列文件的20倍),而从数据库读取时间序列的速度会非常慢,可能比存储在文件中慢一个数量级。而且,这样做并不会给你带来什么重要的好处。你可能根本不会查询“给我所有值大于X的时间序列记录”。如果你真的需要这样的查询,你还需要进行其他复杂的分析,而关系型数据库并不是为此设计的,所以你最终还是得把整个时间序列读入某个对象中。
所以,每个时间序列应该存储为一个文件。这个文件可以是文件系统中的一个文件,或者是数据库中的一个二进制大对象(blob)。尽管我已经实现了后者,但我认为前者更好;在Django中,我会写类似这样的代码:
class Timeseries(models.model):
name = models.CharField(max_length=50)
time_step = models.ForeignKey(...)
other_metadata = models.Whatever(...)
data = models.FileField(...)
使用FileField
可以让你的数据库变小,也更容易进行增量备份。而且,通过在文件中查找,你可以更容易地获取数据片段,这在处理blob时可能会很困难或不可能。
那么,什么样的文件比较好呢?我建议你看看pandas。它是一个用于数学分析的Python库,支持时间序列,并且应该有方法可以将时间序列存储在文件中。
我上面提到的一个库我不推荐你使用;一方面它不能满足你的需求(它无法处理小于一分钟的粒度,还有其他缺陷),另一方面它已经过时了——我在pandas出现之前就写了它,未来我打算把它转换为使用pandas。有一本书叫《Python数据分析》,是pandas作者写的,我觉得非常有用。
更新(2016年):还有InfluxDB。我没用过,所以没有意见,但如果你在考虑如何存储时间序列,这绝对是值得研究的。
更新(2020年2月7日):还有TimescaleDB,这是PostgreSQL的一个扩展。
更新(2020年8月7日):我们又一次更改了软件,现在使用TimescaleDB在数据库中存储数据。我们已经熟悉PostgreSQL,学习TimescaleDB也很简单。最重要的具体好处是,我们可以进行像“查找2019年内24小时内降雨量超过50mm的所有地点”这样的查询,而在存储数据为平面文件时,这会非常困难。另一个好处是完整性检查——多年来我们有几条时间序列因为一些小错误而出现重复行。缺点也很明显。它占用的磁盘空间是之前的10倍。我们可能需要改变PostgreSQL的备份策略。速度也变慢了。检索一条有30万条记录的时间序列可能需要一秒钟,而之前是瞬间完成的。我们需要实现缓存来检索时间序列,而之前是不需要的。