在stackoverflow上检查了很多类似的问题后,似乎上下文会告诉哪种方式最适合保存数据......
简短的故事,我在一个只包含3列的非常简单的表中添加了10,000多个新行数据。我永远不会更新行,只做选择,分组和平均。我正在寻找存储这些数据的最佳方法,以便尽可能快地进行平均计算。
为了让您了解情况,我正在使用FFT分析录制的音频文件(混音室中的粉红噪声播放)。单个音频文件的结果始终采用相同的格式:频率仓的ID(整数)及其分贝值(浮点值)。我想将这些值存储在PostgreSQL数据库中。
频率(宽度= 8Hz)的每个频段(频带)获得以分贝为单位的幅度。第一个bin被忽略,所以它是这样的(不是实际的dB值):
目标是存储每个箱的幅度,从8Hz到20,008Hz(1箱盖8Hz)。
许多行接近
对于每个分析的音频文件,将有2,499行3列:"分析UID"," Bin ID"和" dB"。
对于每个工作室(4),每天有一个记录附加在数据库中(每天4次2,499 = 9,996个新行)。
在一个工作室录制后,新的2,499行用于显示频率响应图。
我担心的是,我们还需要在一个工作室中制作每个箱子的平均dB值5到30天,以查看频率响应是否会随着时间的推移发生显着变化(从而告诉我们工作室需要校准。
我为多行方法提出了以下数据结构:
"分析"表:
" analysis_results"表:
这是存储数据的最佳方式吗?一个表每天保存近10,000个新行,平均分为5个或更多分析,按analyzeUID和freq_bin_ids进行分组?这将给我2,499行(每个行对应一个bin并给出平均dB值)。
许多专栏接近:
我认为我可以反过来打破4个表中的频率区间(低,中低,中高,高)。由于Postgres文档表明列限制为" 250 - 1600,具体取决于列类型" ,因此制作包含大约625列(2,499 / 4)的4个表代表一个是真实的bin并包含" dB"价值,如:
"低"表:
" med_low"表:
等...
如果服务器只需按分析UID分组并计算每列的平均值,那么平均值是否会更快计算?
答案 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)
);