存储数据的最佳方式:对于每天10,000个新行的情况,许多列与多行

时间:2017-04-24 21:16:10

标签: postgresql database-design data-modeling

在stackoverflow上检查了很多类似的问题后,似乎上下文会告诉哪种方式最适合保存数据......

简短的故事,我在一个只包含3列的非常简单的表中添加了10,000多个新行数据。我永远不会更新行,只做选择,分组和平均。我正在寻找存储这些数据的最佳方法,以便尽可能快地进行平均计算。

为了让您了解情况,我正在使用FFT分析录制的音频文件(混音室中的粉红噪声播放)。单个音频文件的结果始终采用相同的格式:频率仓的ID(整数)及其分贝值(浮点值)。我想将这些值存储在PostgreSQL数据库中。

频率(宽度= 8Hz)的每个频段(频带)获得以分贝为单位的幅度。第一个bin被忽略,所以它是这样的(不是实际的dB值):

  • bin 1:8Hz-16Hz,-85.0dB
  • bin 2:16Hz-32Hz,-73.0dB
  • bin 3:32Hz-40Hz,-65.0dB
  • ...
  • bin 2499:20,000Hz-20,008Hz,-49.0dB

目标是存储每个箱的幅度,从8Hz到20,008Hz(1箱盖8Hz)。

许多行接近

对于每个分析的音频文件,将有2,499行3列:"分析UID"," Bin ID"和" dB"。

对于每个工作室(4),每天有一个记录附加在数据库中(每天4次2,499 = 9,996个新行)。

在一个工作室录制后,新的2,499行用于显示频率响应图。

我担心的是,我们还需要在一个工作室中制作每个箱子的平均dB值5到30天,以查看频率响应是否会随着时间的推移发生显着变化(从而告诉我们工作室需要校准。

我为多行方法提出了以下数据结构:

"分析"表:

  • analysisUID(serial)
  • studioUID(外键)
  • analysisTimestamp

" analysis_results"表:

  • analysisUID(外键)
  • freq_bin_id(整数)
  • amplitude_dB(float)

这是存储数据的最佳方式吗?一个表每天保存近10,000个新行,平均分为5个或更多分析,按analyzeUID和freq_bin_ids进行分组?这将给我2,499行(每个行对应一个bin并给出平均dB值)。

许多专栏接近:

我认为我可以反过来打破4个表中的频率区间(低,中低,中高,高)。由于Postgres文档表明列限制为" 250 - 1600,具体取决于列类型" ,因此制作包含大约625列(2,499 / 4)的4个表代表一个是真实的bin并包含" dB"价值,如:

"低"表:

  • analysisUID(外键)
  • freq_bin_id_1_amplitude_dB(float)
  • freq_bin_id_2_amplitude_dB(float)
  • ...
  • freq_bin_id_625_amplitude_dB(float)

" med_low"表:

  • analysisUID(外键)
  • freq_bin_id_626_amplitude_dB(float)
  • freq_bin_id_627_amplitude_dB(float)
  • ...
  • freq_bin_id_1250_amplitude_dB(float)

等...

如果服务器只需按分析UID分组并计算每列的平均值,那么平均值是否会更快计算?

2 个答案:

答案 0 :(得分:1)

行不会成为问题,但是,插入所述行的方式可能是。如果插入时间是主要问题之一,那么请确保您可以批量插入它们或使用较少行的格式。

您可以以jsonb格式存储所有数据,尤其是因为您不会对数据进行任何更新 - 将它们一次全部存储在一个表中可能会很方便,但性能可能会更低

在任何情况下,由于您没有更新数据,因此(通常是默认的)fillfactor为100是合适的。

我不会使用“多列”方法,因为 你所谈论的数据量确实不是那么多。使用2个表和几列的第一个示例很可能是获得结果的最佳方式。

索引以下列可能很有用: analysis_results.freq_bin_id analysis.analysisTimestamp

至于将数据分成不同的部分,它将取决于您正在运行的查询类型。如果您正在查看所有频率分档,那么使用多个表格只会让您感到麻烦并且无需网络。

如果一次仅查询一些freq_bin,理论上可能会有所帮助,但是,你基本上做了表分区,一旦你进入那片土地,你也可以为每个频段做一个分区。 / p>

如果我是你,我会创建你的第一个表结构,用30天的数据填充它并查询。您可能(我们经常这样做)过度分析情况。 Postgres可以非常非常快。

请记住,您正在分析的原始数据是绝对最大值的每天几(5或更少)的数量级。分析150 MB的数据对于使用现代硬件运行的数据库来说,如果它被正确索引和存储,就没有任何问题。

优化器将在“较小”表中找到正确的行,非常快,并且可能会缓存所有这些行,然后去查找子行,并且它将确切地知道要搜索的ID和范围。如果您的数据全部按时间顺序插入,那么很有可能只需很少的读取就可以读取所有数据。

我主要担心的是插入速度,如果你没有进行批量插入,那么做10,000次插入可能需要一段时间。

答案 1 :(得分:0)

由于测量结果表现良好,您可以使用数组,使用freq_bin作为索引(注意:索引在sql中基于1) 这具有额外的优点,即将aray存放在烘烤的存储器中,使得物理桌面保持较小。

CREATE TABLE herrie
    ( analysisUID serial NOT NULL PRIMARY KEY
    , studioUID INTEGER NOT NULL REFERENCES  studio(studioUID)
    , analysisTimestamp TIMESTAMP NOT NULL
    , decibels float[]      -- array with 625 measurements
    , UNIQUE (studioUID,analysisTimestamp)
    );