2017-04-24 49 views
0

在檢查了很多關於stackoverflow的類似問題之後,似乎上下文會告訴哪種方式最適合保存數據。存儲數據的最佳方式:對於每天有10,000個新行的情況,許多列vs多行

小故事,我在僅包含3列的非常簡單的表格中添加了10,000多條新數據行。我永遠不會更新行,只做選擇,分組和平均。我正在尋找存儲這些數據的最佳方法,以便儘可能快地進行平均計算。

爲了把你放在上下文中,我正在使用FFT分析錄製的音頻文件(混音室中的粉紅噪聲播放)。單個音頻文件的結果總是採用相同的格式:頻率點的ID(整數)和以分貝(浮點值)表示的值。我想將這些值存儲在PostgreSQL數據庫中。

頻率(寬度= 8Hz)的每個頻段(頻段)以分貝爲單位獲得振幅。第一倉被忽略,所以它是這樣的(而不是實際的分貝值):

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

的目標是通過存儲來自8HZ每個倉的幅度20,008Hz(1 bin覆蓋8Hz)。

許多行接近

對每一個打開的音頻文件,將有2499行3列:「分析UID」,「賓ID」和「分貝」。

對於每個工作室(4),每天有一個記錄要附加到數據庫中(這是每天2,499 = 9,996個新行的4倍)。

在一個錄音室錄音後,新的2,499行用於顯示頻率響應圖。

我的問題是,我們還需要繪製一個工作室中每個箱子的平均dB值5-30天,以查看頻率響應是否會隨着時間顯着變化(從而告訴我們演播室需要校準)。

我想出了許多行的做法如下數據結構:

「分析」 表:

  • analysisUID(串行)
  • studioUID(外鍵)
  • analysisTimestamp

「analysis_results」表:

  • analysisUID(外鍵)
  • freq_bin_id(整數)
  • amplitude_dB(浮動)

這是存儲數據的最佳方式?一個表格每天保存近10,000個新行,並進行5次或更多次分析的平均值分析,按analysisUID和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(浮動)
  • freq_bin_id_2_amplitude_dB(浮動)
  • ...
  • freq_bin_id_625_amplitude_dB(浮動)

「med_low」 表:

  • analysisUID(外鍵)
  • freq_bin_id_626_amplitude_dB(浮動)
  • freq_bin_id_627_amplitude_dB(浮動)
  • ...
  • freq_bin_id_1250_amplitude_dB(float)

等等

會的平均值來計算速度更快,如果服務器只能通過analysisUIDs有集團,使每一列的平均值?

回答

1

行不會是一個問題,但是,您插入所述行的方式可能是。如果插入時間是主要問題之一,那麼請確保您可以批量插入它們,或者選擇行數較少的格式。

您可以將所有數據以jsonb格式存儲,特別是因爲您不會對數據進行任何更新 - 一次可以將所有數據全部存儲在一張表中,但性能可能會減。

在任何情況下,由於您沒有更新數據,所以100的fillfactor(通常是默認值)是適當的。

我不會使用「多列」方法,因爲您所談論的數據量實際上並不是那麼多。使用你的第一個2個表格和幾列的例子很可能是做你的結果的最佳方式。

這可能是有用的指標以下幾列: analysis_results.freq_bin_id analysis.analysisTimestamp

至於將數據拆分成不同的部分,這將取決於什麼類型的你正在運行的查詢。如果你正在查看所有freq bin,使用多個表格將會是一件麻煩事,你不需要任何網絡。

如果一次只查詢一些freq_bin,理論上可以提供幫助,但是,您基本上正在進行表格分區,一旦您進入該地區,您也可以爲每個頻段進行分區。

如果我是你,我會創建你的第一個表結構,用30天的數據填充它並查詢。你可能(正如我們經常這樣)過分分析這種情況。 Postgres可以非常非常快。

請記住,您正在分析的原始數據是每天幾個(5或更少)meg的絕對最大值。分析150 MB數據對於使用現代硬件運行的數據庫來說,如果索引和存儲正確,那就毫無意義了。

優化器將在「小」表中找到正確的行,真的非常快,可能會緩存所有這些行,然後查找子行,並且它會準確知道要搜索的ID和範圍對於。如果您的數據全部按照時間順序插入,那麼很有可能只用很少的讀數就可以讀取所有數據。

我主要關注的是插入速度,因爲如果您不進行批量插入操作,10,000次插入可能需要一段時間。

+0

我不知道我在哪裏得到的想法,10,000行是巨大的...我會考慮批量插入肯定的,因爲分析完成後,我想,以顯示其產生的立即繪製(沒有任何平均)。對於一個工作室的多天數據平均時間,我擔心性能。我不會特別針對大量頻率做任何特殊的事情,平均數對於所有頻率都是一樣的,所以我會明確地選擇多行方法。我在你的帖子後閱讀了關於fillfactor的內容,我明白現在是什麼。感謝索引! –

0

由於測量結果似乎表現良好,您可以使用一個數組,使用freq_bin作爲索引(注意:索引在sql中是基於1的) 這具有存儲在烘烤存儲中的附加優勢,保留小桌子。


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) 
    ); 
+0

我從來沒有聽說過pgsql中的數組類型,所以我試了一下。所有我需要的數據是最終AVG每個freq_bin的2個或更多的分析。我想我需要使用「unnest」函數將分貝數組轉換爲實際行,並使用UNION將多個分析連接在一起,如下所示: –

+0

SELECT average_of_two_analysis.freq_bin,AVG(average_of_two_analysis。未分類)FROM ( )選擇row_number()OVER()AS「freq_bin」,first_analysis。* FROM(SELECT analysisUID,unnest(「decibels」)AS unneted FROM herrie WHERE analysisUID = 1)AS「first_analysis」 UNION ALL SELECT AS「second_analysis」 )AS「average_of_two_analysis」 GROUP BY average_of_two_analysis。「freq_bin」()分析結果爲「freq_bin」 ORDER BY average_of_two_analysis。「freq_bin」 –

+0

對於最後一個查詢(比較實際數據的2次分析),大約需要430ms。這似乎不是很長嗎?我喜歡你的想法是將數據放在單個Array列中,將大量數據放在一個地方,我喜歡它的「清潔度」,但我擔心Averages的執行時間 –

相關問題