TimescaleDB数据模型(翻译整理)
内容概览
宽数据模型(宽表)。
窄数据模型(窄表)。
定义
宽表:从字面意义上讲就是字段比较多的数据库表。通常是指业务主题相关的指标、维度、属性关联在一起的一张数据库表。由于把不同的内容都放在同一张表存储,宽表已经不符合三范式的模型设计规范,随之带来的主要坏处就是数据的大量冗余,与之相对应的好处就是查询性能的提高与便捷。这种宽表的设计广泛应用于数据挖掘模型训练前的数据准备,通过把相关字段放在同一张表中,可以大大提高数据挖掘模型训练过程中迭代计算时的效率问题。(一句话,空间换时间,便于训练迭代、减少表关联数量,修改少量数据时不需要该多张表)
窄表:严格按照数据库设计三范式。尽量减少数据冗余,但是缺点是修改一个数据可能需要修改多张表
宽数据模型(宽表)
TimescaleDB 很容易支持宽表模型。在此模型中,跨多个指标的查询更容易,因为它们不需要 JOIN。此外,摄取速度更快,因为只为多个指标编写了一个时间戳。
一个典型的宽表模型将匹配一个典型的数据流,其中在给定的时间戳收集多个指标:
timestamp | device_id | cpu_1m_avg | free_mem | temperature | location_id | dev_type |
---|---|---|---|---|---|---|
2017-01-01 01:02:00 | abc123 | 80 | 500MB | 72 | 42 | field |
2017-01-01 01:02:23 | def456 | 90 | 400MB | 64 | 42 | roof |
2017-01-01 01:02:30 | ghi789 | 120 | 0MB | 56 | 77 | roof |
2017-01-01 01:03:12 | abc123 | 80 | 500MB | 72 | 42 | field |
2017-01-01 01:03:35 | def456 | 95 | 350MB | 64 | 42 | roof |
2017-01-01 01:03:42 | ghi789 | 100 | 100MB | 56 | 77 | roof |
在这里,每一行都是一个新读数,在给定时间具有一组测量值和元数据。这使我们能够保留数据中的关系,并提出比以前更有趣或探索性的问题。
当然,这不是一种新格式:它是关系数据库中常见的格式。
加入关系数据
TimescaleDB 的数据模型与关系型数据库还有一个相似之处:它支持 JOIN。具体来说,可以将其他元数据存储在辅助表中,然后在查询时使用该数据。
在我们的示例中,可以有一个单独的位置表,映射location_id
到该位置的其他元数据。例如:
location_id | name | latitude | longitude | zip_code | region |
---|---|---|---|---|---|
42 | Grand Central Terminal | 40.7527° N | 73.9772° W | 10017 | NYC |
77 | Lobby 7 | 42.3593° N | 71.0935° W | 02139 | Massachusetts |
然后在查询时,通过连接我们的两个表,可以提出以下问题:free_mem
我们的设备在zip_code
10017 中的平均值是多少?
如果没有连接,则需要对其数据进行非规范化并将所有元数据存储在每个测量行中。这会造成数据膨胀,并使数据管理更加困难。
通过联接,可以独立存储元数据,并更轻松地更新映射。
例如,如果我们想更新location_id
77 的“区域”(e.g., from "Massachusetts" to "Boston"),我们可以进行此更改,而无需返回并覆盖历史数据。
窄数据模型(窄表)
大多数时间序列数据库会以下列方式表示这些数据:
将每个指标表示为一个单独的实体(例如,将cpu_1m_avg 和表示free_mem为两个不同的事物)为该指标存储一系列“时间”、“值”对将元数据值表示为与该指标/标签集组合关联的“标签集”在这个模型中,每个度量/标签集组合都被认为是一个单独的“时间序列”,其中包含一系列时间/值对。
使用我们上面的示例,这种方法将产生 9 个不同的“时间序列”,每个“时间序列”都由一组的标签定义。
1. {name: cpu_1m_avg, device_id: abc123, location_id: 335, dev_type: field}
2. {name: cpu_1m_avg, device_id: def456, location_id: 335, dev_type: roof}
3. {name: cpu_1m_avg, device_id: ghi789, location_id: 77, dev_type: roof}
4. {name: free_mem, device_id: abc123, location_id: 335, dev_type: field}
5. {name: free_mem, device_id: def456, location_id: 335, dev_type: roof}
6. {name: free_mem, device_id: ghi789, location_id: 77, dev_type: roof}
7. {name: temperature, device_id: abc123, location_id: 335, dev_type: field}
8. {name: temperature, device_id: def456, location_id: 335, dev_type: roof}
9. {name: temperature, device_id: ghi789, location_id: 77, dev_type: roof}
这种时间序列的数量与每个标签的基数的叉积成比例,即(#names)×(#device ids)× (#location ids)× (device *)。随着基数的增加,一些时间序列数据库会遇到困难,终限制了您可以存储在单个数据库中的设备类型和设备的数量。
TimescaleDB 支持窄模型,并且不会受到与其他时间序列数据库相同的基数限制。如果您独立收集每个指标,那么一个狭窄的模型是有意义的。它允许您通过添加新标签随时添加新指标,而无需正式更改架构。
但是,如果您要收集许多具有相同时间戳的指标,则窄模型的性能会降低,因为它需要为每个指标编写时间戳。这终会导致更高的存储和摄取要求。此外,关联不同指标的查询也更加复杂,因为您想要关联的每个附加指标都需要另一个 JOIN。如果您通常一起查询多个指标,那么将它们存储在宽表格式中既更快又更容易。
来源 https://mp.weixin.qq.com/s/mxIqa4o8JjPHqTMi9nAS9w
相关文章