高效存储时间序列数据,不浪费空间

car*_*rdy 6 mysql database-design time

我正在构建一个应用程序来计算电子商务网站客户的不同KPI 指标,例如(平均订单价值、平均项目数等)。KPI 是整数和/或双值,例如购买的商品数量、平均值。订单价值、毛利率...

该应用程序获取订单数据、计算指标并存储它们。我使用 MySQL 作为关系数据库。

关于指标:

我目前有 10 个指标要为每个客户计算。

指标在未来可能会增加,但不会那么频繁,所以我可以认为“10”是非常确定的。无论如何,将来更改架构根本不是问题。

我需要每周(至少)计算每个指标。指标是关于客户的。

关于客户:

客户有 30k,并且以每月 0.5k 的速度增长。

并非所有客户都以相同的频率购买。我可以有偶尔的买家,但也有重度买家。

我想显示一个图表,其中包含给定时间跨度内特定 KPI 的总体趋势。

我想显示一个图表,其中包含给定时间跨度内特定客户的指标趋势。

我的实体是:

  • 订单
  • 顾客
  • 客户_kpi

我担心存储大量无用数据

52 周 * 30k 用户 * 4+ 年 = 至少 620 万行

我有两个问题:

  1. 我是否应该在给定的时间跨度内为没有订单的客户存储行(例如,该行将全部填充为 NULL)?可以在不影响数据可视化的情况下以某种方式避免它吗?

  2. 考虑到并非所有客户每周都购买并且指标数量不太可能经常更改,哪种表结构更有效(“瘦”表与“胖”表)?

我对customers_kpi表的这两个结构存有疑问:

顾客ID kpi1 kpi2 kpi3 ..kpiN

VS

顾客ID kpi_name kpi_value

J.D*_*.D. 5

首先,几百万行没什么好害怕的。如果架构和索引正确,现代关系数据库管理系统可以在相当标准的硬件上处理多达数万亿行。其次,我喜欢以至少 10 年的时间来衡量事物,作为一个很好的时间测试,所以让我们采用你的指标并在 10 年内对其进行年化,这使我们接近约 1560 万行,让我们将其四舍五入为 2000 万(考虑客户增长等)。就单个表中的记录数量而言,我们仍然处于中等规模,所以没什么大不了的。

直接回答您的问题:

1.我是否应该为给定时间跨度内没有订单的客户存储行(例如,该行将全部填充为NULL)?是否可以在不影响数据可视化的情况下以某种方式避免它?

答:不需要存储空行。您可以创建一个日期维度表,该将为每个日期存储一行,然后您可以外部连接到它,例如SELECT * FROM dateDimensions AS D LEFT OUTER JOIN orders AS O ON D.date = O.orderDate WHERE D.date >= 'some date value' AND D.date < 'some other date value'. (您可以根据需要在此处加入其他表。)这将有助于使您的表更加精简(也许 10 年内的 2000 万行大约会变成 1000 万或 500 万行),因为现在您没有存储多个ordercustomer_kpi行或空行每周对于每个customer没有创建 的人order,您每个日期只存储一行(或者您的日期维度表甚至可以简化为每周只存储一行 - 尽管可能有点矫枉过正)。外部连接到您的日期维度表将保持您正在寻找的相同可视化。

2.考虑到并非所有客户每周都会购买并且指标数量不太可能经常更改,哪种表结构更有效(“瘦”表与“胖”表)?

答:这两种表结构都有自己的位置,有时像第一个示例结构这样的非规范化表结构对于OLAP重/重报告数据库的性能更好,但一般来说,当所有条件都相同时,规范化是最佳实践,就像你的第二个示例结构体。因为 2000 万行(基于我对第一个问题的回答的最坏情况下的行数)在单个表中确实没有什么可担心的,并且因为您可以通过仅查询特定KPI获得更好的灵活性(可以通过以下方式获得更高的性能)没有带回一堆不需要的数据的行),例如SELECT * FROM customers_kpi WHERE kpi_name = 'SomeSpecificKPI',我个人建议从您的第二个表结构开始。如果您需要或应该改变主意并希望将其作为该结构具体化为新表格,您可以随时轻松地将其转换为您的第一个结构。