web-dev-qa-db-ja.com

PostgreSQL byteaとsmallint []

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

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

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

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

9
beldaz

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

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

Vanilla構成の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で示します。 Storage cost in MB

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

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

アクセスコストに関しては、これをいじりませんでしたが、少なくともデータを挿入するという点では、最初に最速の表現はEpochByteaBlobFileで、EpochChannelArray最も遅く、最初の2つの約3倍の時間がかかります。

11
beldaz