在PostgreSQL中表示稀疏数据

Cer*_*rin 18 sql postgresql relational-database sparse-matrix

在PostgreSQL中表示稀疏数据矩阵的最佳方法是什么?我看到的两个明显的方法是:

  1. 将数据存储在单个表中,每个表都有一个单独的列(可能是数百万),但未使用的功能的默认值为NULL.这在概念上非常简单,但我知道在大多数RDMS实现中,这通常非常低效,因为NULL值通常会占用一些空间.但是,我读了一篇文章(遗憾的是找不到它的链接),声称PG没有占用NULL值的数据,使其更适合存储稀疏数据.

  2. 创建单独的"行"和"列"表,以及用于链接它们并在该行存储列值的中间表.我相信这是更传统的RDMS解决方案,但它有更多的复杂性和开销.

我还发现了PostgreDynamic,它声称可以更好地支持稀疏数据,但我不想仅仅为了这个功能而将整个数据库服务器切换到PG分支.

还有其他解决方案吗?我应该使用哪一个?

Teb*_*bas 15

我假设您正在考虑数学上下文中的稀疏矩阵:http: //en.wikipedia.org/wiki/Sparse_matrix(其中描述的存储技术用于存储器存储(快速算术运算),而不是持久存储(低磁盘)用法).)

由于人们通常在客户端而不是服务器端对此矩阵进行操作,因此SQL-ARRAY []是最佳选择!

问题是如何利用矩阵的稀疏性?这里是一些调查的结果.

建立:

  • Postgres 8.4
  • 矩阵具有400*400个双精度元素(8字节) - 每个矩阵的原始尺寸> 1.28MiB
  • 33%的非零元素 - >每个矩阵有效大小为427kiB
  • 使用~1000个不同的随机填充矩阵进行平均

竞争方法:

  • 依靠SET STORAGE MAIN或EXTENDED对列的自动服务器端压缩.
  • 仅存储非零元素以及描述在矩阵中定位非零元素的位置的位图(bit varying(xx)).(一个双精度比一位大64倍.理论上(忽略开销),如果<= 98%非零,则该方法应该是改进;-).)服务器端压缩被激活.
  • 用NULL 替换矩阵中的零.(RDBMS在存储NULL方面非常有效.)服务器端压缩已激活.

(使用第二个索引-ARRAY []索引非零元素并不是很有希望,因此没有经过测试.)

结果:

  • 自动压缩
    • 没有额外的实施努力
    • 没有减少网络流量
    • 压缩开销最小
    • 持久存储=原始大小的39%
  • 位图
    • 可接受的实施工作
    • 网络流量略有下降; 依赖于稀疏性
    • 持久存储=原始大小的33.9%
  • 用NULL替换零
    • 一些实现工作(API需要知道在构造INSERT查询时在ARRAY []中设置NULL的位置和方式)
    • 网络流量没有变化
    • 持久存储=原始大小的35%

结论:从EXTENDED/MAIN存储参数开始.如果您有空闲时间调查您的数据并使用我的测试设置与稀疏级别.但效果可能低于您的预期.

我建议总是使用矩阵序列化(例如,行主要顺序)加上两个整数列作为矩阵维度NxM.由于大多数API使用文本SQL,因此您可以为嵌套的"ARRAY [ARRAY [..],ARRAY [..],ARRAY [..],ARRAY [..],..]"节省大量网络流量和客户端内存. !

Tebas


CREATE TABLE _testschema.matrix_dense
(
  matdata double precision[]
);
ALTER TABLE _testschema.matrix_dense ALTER COLUMN matdata SET STORAGE EXTERN;


CREATE TABLE _testschema.matrix_sparse_autocompressed
(
  matdata double precision[]
);

CREATE TABLE _testschema.matrix_sparse_bitmap
(
  matdata double precision[]
  bitmap bit varying(8000000)
);
Run Code Online (Sandbox Code Playgroud)

将相同的矩阵插入所有表中.具体数据取决于特定表.由于未使用但已分配的页面,请勿更改服务器端的数据.或做一个VACUUM.

SELECT 
pg_total_relation_size('_testschema.matrix_dense') AS dense, 
pg_total_relation_size('_testschema.matrix_sparse_autocompressed') AS autocompressed, 
pg_total_relation_size('_testschema.matrix_sparse_bitmap') AS bitmap;
Run Code Online (Sandbox Code Playgroud)


MkV*_*MkV 8

一些解决方案浮现在脑海中,

1)将您的功能分成通常设置在一起的组,为每个组创建一个表,与主数据具有一对一的外键关系,仅在查询时加入表所需的表

2)使用EAV反模式,使用主表中的外键字段以及字段名和值列创建"功能"表,并将功能存储为该表中的行而不是主表中的属性表

3)与PostgreDynamic的工作方式类似,为主表中的每个"列"创建一个表(它们为这些表使用单独的命名空间),并创建函数以简化(以及有效索引)访问和更新数据那些表

4)使用XML或VARCHAR在主数据中创建一个列,并在其中存储表示数据的一些结构化文本格式,使用功能索引创建数据索引,编写更新数据的函数(或者如果您使用XML函数正在使用那种格式)

5)使用contrib/hstore模块创建一个类型为hstore的列,该列可以保存键值对,并且可以索引和更新

6)住着很多空地

  • 它抛弃了数据库、行级约束和参照完整性的所有优点,并且很难为单个实体返回单行。 (2认同)