时间序列:SQL 还是 NoSQL?

Nic*_*las 34 nosql

我不关心 SQL 和 NoSQL 之间的一般差异(或它们的传统差异)。

我目前正在考虑改变我们内部时间序列的存储。它们都包含来自许多不同来源的财务数据。目前,我们将数据存储在专有数据库中。它非常像 NoSQL,它有自己的查询语言。

我对社区输入很感兴趣:您将如何将数据存储在 SQL 数据库中?在 NoSQL 上使用 SQL 有什么优点,特别是对于时间序列?考虑将它存储在 SQL 中,我疯了吗?

我们的数据集由数百万个时间序列组成,其中大约 10% 每个包含数百万条记录。时间序列按层次结构组织:/Market/Instrument/Value/Frequency,其中:

  • 市场是证券交易所等,基本上是工具的集合,通常是类似的工具。
  • 乐器是乐器。这可能是一个指标(布伦特原油)、一个股票(GOOG)等
  • 值是工具的多种数据类型之一。这可能是收盘价、最高价、最低价等
  • 频率是特定时间序列值的频率。每周、每天、每月、滴答、任意等。

数据将如何存储在 SQL 数据库中?一张大表(可能被某些东西分区),每个市场或工具一张表,每个时间序列一张表。

先感谢您。

小智 26

一般来说,对于这样的结构化数据集,我怀疑您可以编写一种自定义数据格式,该格式对于大多数日常操作(即从任意时间提取小数据)速度更快。迁移到标准数据库工具的好处可能体现在一些附加功能中,例如临时查询、多重访问、复制、可用性等。聘请帮助来维护基于标准的数据存储也更容易。

如果我被要求建立一个数据库来存储该数据,我会执行以下操作:

提议的模式

(1) 核心数据被放入无数(1000 个)单独的表中,每个表包含两列:

  1. 时间:SQL DATETIME 数据类型或某个时期的数字类型(这是主键)
  2. 值:根据您的数据键入。我会默认为单精度浮点数,但定点数据类型可能更适合金融交易。这可能是未编入索引的。

这些表会变得非常大,您可能希望按(例如)年份手动对它们进行分区。但是您必须检查系统性能并进行适当调整。

这些表需要唯一的名称,并且有几个选项。它们可以是人类可读的(例如 nyse_goog_dailyhighs_2010)或(我的偏好)随机的。无论哪种方式都需要一组元数据表,并且随机表名可以防止开发人员将任何不应该被推断的名称推断出。

(2) 根据应用程序的要求,元数据存储在单独的表中

需要一个额外的表或一组表来跟踪元数据。这些表格将包含有关交易所、工具、价值、频率、日期范围、来源(数据来自何处)以及您需要的任何其他数据。这些映射到数据表名称。

如果有足够的数据,这个查找实际上可以提供一个表名和数据库名,允许一种自我实现的数据分片(如果这是该术语的正确用法)。但我会保留它。

然后在应用层我会查询元数据表以确定我的数据所在的位置,然后在大数据表上执行相对简单的查询来获取我的数据。

好处:

  • 我(相对有限)的经验是,数据库通常比处理少量大表更容易处理大量小表。这种方法还使维护更容易(例如清除旧数据、重建损坏的表、从备份创建/重新加载、添加新实体)。这完全解耦了不同类型的数据,如果(例如)您有不同速率的数据,或者需要不同的数据类型。

  • 这个瘦表概念还应该允许对我怀疑是最常见查询的快速磁盘访问,来自单个实体的连续数据范围。大多数数据应用程序都受磁盘 I/O 限制,因此值得考虑。正如评论者已经暗示的那样,这是面向列的数据库的理想应用程序,但我还没有找到一种足以让我打赌我的职业生涯的面向列的产品。这个模式非常接近。

缺点:

  • 大约一半的磁盘空间专用于存储时间戳,坦率地说,100 个或 1000 个表在时间戳列中具有完全相同的数据。(事实上​​,如果您想执行简单的表连接,这是一个要求)。

  • 存储表名和执行动态查找需要大量的应用程序复杂性和字符串操作,这让我感到畏缩。但它似乎仍然比替代方案(下面讨论)更好。

注意事项:

  • 小心在您的时间字段中四舍五入。您希望您的值足够圆以启用连接(如果适用),但又足够精确以明确无误。

  • 注意时区和夏令时。这些很难测试。我会在数据存储上强制执行 UTC 要求(这可能会让我不受欢迎)并处理应用程序中的转换。

变化:

我考虑过的一些变化是:

数据折叠: 如果时间序列等距,则使用一个时间戳列和(例如)10 个数据列。时间戳现在指的是第一个数据列的时间,并且假设其他数据列在该时间戳和下一个时间戳之间等距。这以显着的查询和/或应用程序复杂性为代价,节省了大量以前用于存储时间戳的存储空间。连续范围的单个实体查询现在需要更少的磁盘访问。

多路复用如果已知多个时间序列使用相同的时间序列,则使用一个时间戳和(例如)如上所述的 10 个数据列。但是现在每列代表一个不同的时间序列。这需要更新元数据表,而不是查找表和列名。存储空间减少。查询仍然很简单。无论范围如何,单个实体查询现在都需要更多的磁盘访问。

Mega-table: 将“多路复用”的概念发挥到极致,将所有数据放到一个表中,每列一个时间序列。这需要对连续范围、单个实体查询进行大量磁盘访问,并且是维护的噩梦。例如,添加新实体现在需要在多 TB 表上执行 MODIFY TABLE 命令。

有关此格式的其他讨论,请参阅: MySQL 中的列太多

完全规范化的表: 您可以使用一列三列的表,而不是使用许多 2 列表,其中列是时间、数据 ID 和值。现在您的元数据表只需要查找 ID 值,而不是表名或列名,这可以将更多逻辑推入 SQL 查询,而不是应用程序层。

现在标准化列消耗了大约 2/3 的存储空间,因此这将使用大量磁盘空间。

您可以使用 (dataid, timestamp) 的主键顺序进行快速连续的单个实体查询。或者,您可以使用 (timestamp.dataid) 的主键顺序进行更快的插入。

然而,即使在考虑了这些变化之后,我的下一个开发计划还是很多表格,每个表格有两列。那,或者很快就会被比我更聪明的人发布的方法:)。