Django + Postgres + 大型时间序列

22

我正在研究一个涉及大量、大多数无法压缩的时间序列数据的项目,并想知道是否使用Django + Postgres和原始SQL是正确的选择。

我有时间序列数据,每小时约2K个对象。这意味着我每年存储约200万行数据,并且我希望能够通过连接切片数据进行分析,以及能够通过Django提供的网页进行基本概述工作。我认为最好的方法是使用Django处理对象本身,但是使用原始SQL来处理关联的大型时间序列数据。我认为这是一种混合方法;这可能是一个警示信号,但对于长时间序列数据样本使用完整的ORM感觉过于浪费。是否有更好的方法?

4个回答

31
如果我正确理解了您的想法,您正在考虑将时间序列存储在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 for data analysis",由pandas的作者撰写,我发现它非常有价值。
更新(2016年):还有InfluxDB。我从未使用过它,因此我没有意见,但如果你想知道如何存储时间序列,那么它绝对是你需要检查的东西。

更新(2020年2月7日):还有TimescaleDB,这是PostgreSQL的一个扩展。

更新(2020年8月7日):我们再次更改了软件,以便使用TimescaleDB将数据存储在数据库中。我们已经熟悉PostgreSQL,并且很容易学习一些TimescaleDB。最重要的具体优点是,我们可以进行查询,例如“查找所有在2019年内24小时内降雨量>50mm的位置”,这在存储数据时使用平面文件会非常困难。另一个优点是完整性检查 - 多年来,由于这里那里的小错误,我们有一些带有重复行的时间序列。缺点也很明显。它使用10倍的磁盘空间。因此,我们可能需要更改我们的PostgreSQL备份策略。它更慢。检索具有300k记录的时间序列可能需要一秒钟。这以前是立即完成的。我们需要实现缓存以检索时间序列,这以前不需要。


我不确定文件是否适用于我的用例。我正在查看天气数据,因此我会获取以下几个方面的切片:1)少数地点的所有历史记录,2)所有地点在较短的历史时间段内(一个月!),以及3)某一时间段内所有位置的最大值。(由于天气与时间和地点相关,不同的地点可以有意义地相互影响。)如果我使用的文件实现是按地点为主(每个地点都有一个文件)或按时间为主(每天/每周/每月都有一个文件),那么如果我提取上述类型的切片,我将不得不触及所有文件。数据库肯定行不通吗? - Ben
我误解了你;我以为你有一个每小时2k行的时间序列;现在我明白了,你有一组在2k个位置上每小时的时间序列。然而,我的观点并没有改变。不,关系型数据库不是绝对无法工作的,我相信已经有成功的应用程序使用它编写。但是我认为它是次优的。然而,这可能适合于你。我看到pandas具有将数据读取和写入数据库的功能。 - Antonis Christofides
你认为对于开盘价、最高价、最低价和收盘价的数据也是这样吗?我正在研究时间序列,但将其存储为Pandas数据框架会让我的工作变得更加容易。 - Aran Freel
我不是很确定。我有一些代码可以从数据库读取到pandas,反之亦然,也可以从文件读取到pandas,反之亦然。 - Antonis Christofides
请注意查看VictoriaMetrics。很有可能它会在更低的资源使用率下展现出更好的性能,适用于您的工作负载。 - valyala

12

时间序列数据库似乎是那些不断被重新发明的事情之一,而如上所示,关系型数据库并不适合。

我的做法是将 Django 与 InfluxDB 结合起来,后者专门用于时间序列数据。它非常好用,Python 客户机库可以与 pandas 数据帧一起使用。这意味着您可以使用 InfluxDB 查询语言在原地处理数据,或者将所有数据(如果需要聚合)拉入 Python 进行分析。我的应用程序正在处理类似于您所需的数据流量。

我将 InfluxDB 系列名称与 django 应用程序/模型/主键按需进行关联。时间序列数据放入链接的 InfluxDB 系列中,杂项缓慢变化或关系数据放入 Django ORM 字段中。


5

听起来你想了解一下timescale。我自己还没有使用过它,但显然它是PostgreSQL的扩展,所以我认为它完全支持Django,并且可以处理他们所说的

每秒数百万个指标和数十万行数据,即使在单个节点上达到1000亿行。


0
您可能还考虑使用PostGIS postgres扩展,它包括对栅格数据类型(基本上是大量数字网格)的支持,并具有许多功能可供使用。
但在这种情况下不要使用ORM,您需要直接在服务器上执行SQL。ORM会给大型数值数据集添加大量开销。它也不太适合在Python中处理大型矩阵,需要用到numpy。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接