PostgreSQL bytea与smallint []


9

我希望将大型(100Mb-1 GB)多通道时间序列数据导入PostgreSQL数据库。数据来自EDF格式文件,该文件将数据分块为通常每个几秒钟的“记录”或“纪元”。每个时期的记录将每个数据通道的信号保存为短整数的连续数组。

我被授权将文件存储在数据库中,在最坏的情况下,存储为BLOB。鉴于此,我想研究一些选项,这些选项将使我可以对数据库中的数据做更多的事情,例如,促进基于信号数据的查询。

我最初的计划是将每个纪元记录的数据存储为一行。我要权衡的是将实际信号数据存储为bytea还是smallint [](甚至是smallint [] [])类型。谁能推荐一个?我对存储和访问成本感兴趣。用法可能只插入一次,偶尔读取,就永远不会更新。如果更容易将其包装为自定义类型,以便我可以添加用于分析比较记录的函数,那就更好了。

毫无疑问,我的细节不够完善,请随时添加您要我澄清的内容的评论。


2
这可能是在权威数据模型中使用数组的几种明智用途之一,因为通过避免24到28字节的行开销可以节省大量磁盘空间。如果足够长的话,数组也将被压缩并离线存储。
Craig Ringer 2015年

beldaz,您存储数据的方式与计划访问方式以及访问频率有很大关系。如果很少查询数据,而您始终只想按每个记录提取数据,那么我认为数组中每个记录的一行是很有意义的。但是,如果您希望进行任何更深入的查询,例如为给定的Patient_id提取所有记录,那么也许我们建议对存储结构进行一点改进。关于您的查询模式有什么想法吗?
克里斯(Chris

@克里斯谢谢。我忽略了元数据组件,因为它很小,可以驻留在单独的关系中。查询模式是TBD,但我可能想比较同时记录的两个不同文件,并从同时出现的时期中提取信号。
beldaz 2015年

@CraigRinger我没有看到很多数组压缩的证据。是否需要以某种方式启用此功能?
beldaz 2015年

Answers:


11

在没有任何答案的情况下,我自己进一步探讨了这个问题。

似乎用户定义的函数可以处理所有基本类型,包括 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)
);

然后,我通过Java JDBC将选择的EDF文件导入到每个关系中,并比较每次上载后数据库大小的增长。

这些文件是:

  • 文件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%,因此,与存储为大对象相比,这并不差。

我最初没有意识到的一件事是PostgreSQL中的“多维数组必须具有每个维的匹配范围” 。这意味着SMALLINT[][]仅当一个时期中的所有通道具有相同数量的样本时,该表示才起作用。因此,文件C无法处理该EpochArray关系。

就访问成本而言,我还没有解决这个问题,但是至少在最初插入数据方面,最快的表示形式是EpochByteaBlobFile,而EpochChannelArray最慢的表示形式是前两个表示形式的三倍。


从学术的角度来看,我发现您的结果非常有趣,但是从实际的角度来看,存储容量是否值得关注?也许在您的用例中,您有很多记录,因此存储是您面临的问题吗?但是,在这种存储格式下,除按纪元(或通道,在适当的模式中)以外的任何查找都需要读取每个记录的一部分。这样适合您的应用程序吗?
克里斯(Chris

实际上,是的,这对我当然很重要,因为我希望处理几个TB的原始文件。事实证明,当前的间接费用低于我的预期,但是如果对于特定的表示,它的费用已达到300%,则我肯定会避免使用它。至于查询,我不希望通过时代和渠道来访问。
beldaz 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.