PostgreSQL byteaとsmallint []


9

大規模な(100Mb-1 GB)マルチチャネル時系列データをPostgreSQLデータベースにインポートしようとしています。データは、通常はそれぞれ数秒の「レコード」または「エポック」にデータを分割するEDF形式のファイルから取得されます。各エポックのレコードは、データの各チャネルの信号を短い整数の順次配列として保持します。

最悪の場合、BLOBとしてデータベース内にファイルを保存するように義務付けられています。そこで、信号データに基づくクエリを容易にするなど、データベース内のデータをさらに活用できるオプションを調査したいと思います。

私の最初の計画は、エポックレコードごとに1行としてデータを格納することです。私が比較検討しているのは、実際の信号データをbyteaまたはsmallint [](またはsmallint [] [])のどちらのタイプとして格納するかです。誰かが他のものを推薦することはできますか?ストレージとアクセスのコストに興味があります。使用法は、1回挿入され、時々読み取られ、決して更新されない可能性があります。レコードを比較して分析するための関数を追加できるように、カスタムタイプとしてより簡単にまとめることができれば、はるかに優れています。

間違いなく私は詳細が低いので、私が明確にしてほしいことについてコメントを追加してください。


2
24〜28 バイトの行オーバーヘッドを回避することにより、多くのディスク領域を節約できるので、これは、信頼できるデータモデルでの配列使用の数少ない賢明な使用の1つかもしれません。配列も十分に長い場合、圧縮されて行外に格納されます。
クレイグリンガー

beldaz、データを保存する方法は、データへのアクセス方法と頻度に大きく関係しています。データがめったに照会されず、常にレコードごとにデータをプルしたい場合は、配列内のレコードごとに1つの行が適切であると思います。ただし、たとえば、特定の患者IDのすべてのレコードを取得するなど、少し詳細なクエリを実行する場合は、ストレージ構造を少し改善することをお勧めします。クエリパターンに関するアイデアはありますか?
Chris

@クリスありがとう。メタデータコンポーネントは非常に小さく、別の関係に存在できるため、省略しました。クエリパターンは未定ですが、同時に記録された2つの異なるファイルを比較し、同時エポックから信号を引き出したい場合があります。
beldaz 2015年

@CraigRinger配列圧縮の証拠はあまり見られませんでした。これは何らかの方法で有効にする必要がありますか?
beldaz 2015年

回答:


11

答えがないので、私は自分で問題をさらに調査しました。

ユーザー定義関数はand を含む すべての基本型を処理できるように見えるため、これは表現の選択にあまり影響しません。byteasmallint[]

バニラ構成のWindows 7ラップトップでローカルに実行されているPostgreSQL 9.4サーバーでいくつかの異なる表現を試してみました。その実際の信号データを格納する関係は以下の通りでした。

ファイル全体のラージオブジェクト

CREATE TABLE BlobFile (
    eeg_id INTEGER PRIMARY KEY,
    eeg_oid OID NOT NULL
);

チャネルごとのSMALLINT配列

CREATE TABLE EpochChannelArray (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    channel INT,
    signal SMALLINT[] NOT NULL,
    PRIMARY KEY (eeg_id, epoch, channel)
);

各エポックのチャネルごとのBYTEA

CREATE TABLE EpochChannelBytea (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    channel INT,
    signal BYTEA NOT NULL,
    PRIMARY KEY (eeg_id, epoch, channel)
);

エポックごとのSMALLINT 2D配列

CREATE TABLE EpochArray (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    signals SMALLINT[][] NOT NULL,
    PRIMARY KEY (eeg_id, epoch)
);

エポックごとのBYTEA配列

CREATE TABLE EpochBytea (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    signals BYTEA NOT NULL,
    PRIMARY KEY (eeg_id, epoch)
);

次に、選択したEDFファイルをJava JDBCを介してこれらの各関係にインポートし、各アップロード後のデータベースサイズの増加を比較しました。

ファイルは次のとおりです。

  • ファイルA:16チャネルの2706エポック、各チャネル1024サンプル(エポックあたり16385サンプル)、85 MB
  • ファイルB:18チャネルの11897エポック、各チャネル1024サンプル(エポックごとに18432サンプル)、418 MB
  • ファイルC:20チャネルの11746エポック、各チャネル64から1024サンプル(エポックあたり17088サンプル)、382 MB

ストレージコストの観点から、それぞれの場合に使用されるサイズ(MB)を以下に示します。 ストレージコスト(MB)

元のファイルサイズに比べて、ラージオブジェクトは約30〜35%大きくなりました。対照的に、各エポックをBYTEAまたはSMALLINT [] []として保存すると、10%小さくなります。各チャネルを個別のタプルとして保存すると、BYTEAまたはSMALLINT []のように40%増加するため、ラージオブジェクトとして保存するよりもはるかに悪くはありません。

私が最初に理解していなかったことの1つは、PostgreSQLの「多次元配列には各次元に一致する範囲がなければならない」ということです。これはSMALLINT[][]、エポック内のすべてのチャネルが同じ数のサンプルを持っている場合にのみ表現が機能することを意味します。したがって、ファイルCはEpochArrayリレーションで機能しません。

アクセスコストなどの面で、私はこれで遊んが、少なくとも最初は最速の表現だったデータを挿入するという点ではなかったEpochByteaBlobFileし、EpochChannelArray最初の2限り、3回ほど取って、最も遅いです。


学術的な観点から、あなたの結果は非常に興味深いと思いますが、実用的な観点から、ストレージサイズは大きな懸念事項ですか?おそらくあなたのユースケースでは非常に多くのレコードがあるので、ストレージはあなたが直面している問題ですか?ただし、このストレージ形式では、エポック(または適切なスキーマの場合はチャネル)以外のルックアップでは、すべてのレコードの一部を読み取る必要があります。これはアプリケーションで問題ありませんか?
Chris

実際にはそうです。数TBのrawファイルを処理することを期待しているので、それは確かに私にとって重要です。オーバーヘッドの電流は予想よりも低いことがわかりましたが、特定の表現で300%だった場合は、それを避けます。クエリに関しては、エポックとチャネル以外のアクセスは期待していません。
beldaz 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.