在PostgreSQL中表示稀疏数据

在PostgreSQL中表示稀疏数据,sql,postgresql,relational-database,sparse-matrix,Sql,Postgresql,Relational Database,Sparse Matrix,在PostgreSQL中表示稀疏数据矩阵的最佳方法是什么?我看到的两种明显的方法是: 将数据存储在单个表中,每个可能的功能(可能有数百万个)都有一个单独的列,但未使用的功能的默认值为NULL。这在概念上非常简单,但我知道在大多数RDMS实现中,这通常是非常低效的,因为空值通常会占用一些空间。然而,我读了一篇文章(不幸的是找不到它的链接),文章声称PG不占用空值的数据,这使它更适合存储稀疏数据 创建单独的“行”和“列”表,以及一个中间表来链接它们,并将列的值存储在该行。我相信这是更传统的RDMS解

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

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

  • 创建单独的“行”和“列”表,以及一个中间表来链接它们,并将列的值存储在该行。我相信这是更传统的RDMS解决方案,但与此相关的复杂性和开销更大

  • 我还发现,它声称可以更好地支持稀疏数据,但我不想为了这个特性而将整个数据库服务器切换到PG fork


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

    空值在为空时不会占用任何空间。它将占用元组头中位图中的一位,但无论如何都会存在

    然而,该系统无法处理数百万个列。理论上最大值是一千多一点,IIRC,但你真的不想走那么远

    如果您真的需要那么多,在一个表中,您需要使用EAV方法,这基本上就是您在(2)中所说的


    如果每个条目只有相对较少的键,我建议您将“hstore”contrib模块作为第三个选项,它可以让您非常高效地存储此类数据。它在即将发布的9.0版本中得到了进一步增强,因此,如果您离生产部署还有一点距离,您可能希望直接查看该版本。然而,在8.4中它也是值得的。它确实支持一些非常有效的基于索引的查找。绝对值得研究。

    我想到了一些解决方案

    1) 将要素分成通常一起设置的组,为每个组创建一个与主数据具有一对一外键关系的表,在查询时仅对需要的表进行联接

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

    3) 与PostgreDynamic的做法类似,为主表中的每个“列”创建一个表(它们为这些表使用单独的命名空间),并创建函数以简化(以及高效地索引)访问和更新这些表中的数据

    4) 使用XML或VARCHAR在主数据中创建列,并在其中存储一些表示数据的结构化文本格式,使用函数索引在数据上创建索引,编写函数更新数据(如果使用该格式,则使用XML函数)

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


    6) 生活在大量的空字段中

    我假设你是从数学的角度考虑稀疏矩阵: (这里描述的存储技术用于内存存储(快速算术运算),而不是持久存储(低磁盘使用率)。)

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

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

    设置:

    • 博士后8.4
    • 矩阵w/400*400双精度元素(8字节)-->每个矩阵的原始大小为1.28MiB
    • 33%非零元素-->每个矩阵427kiB有效大小
    • 使用约1000个不同的随机填充矩阵求平均值
    竞争方法:

    • 通过设置存储主目录或扩展目录,依靠服务器端的自动压缩功能

    • 仅存储非零元素和一个位图(
      位变化(xx)
      ),描述在矩阵中定位非零元素的位置。(一个双精度比一位大64倍。理论上(忽略开销)如果我知道这是一个旧线程,但是为Postgres提供了稀疏向量类型,以及一些机器学习和统计方法,那么这种方法应该是一种改进。

      您还可以创建一个“feature”类型,如featurename VARCHAR、featurevalue VARCHAR(或任何需要的值),并添加feature[]类型的FEATURES字段你为什么称EAV为“反模式”?谷歌搜索显示这是对EAV的一种常见描述(通常使用贬义),但似乎没有人解释原因。似乎有许多有效的情况下,数据库需要存储稀疏数据,例如医疗领域,使EAV成为一种合适的“模式”。它抛弃了数据库、行级约束和引用完整性的所有优点,并使为单个实体返回单个行变得困难。@Cerin:EAV是一种反模式。它一开始看起来是骗人的,但从长远来看却是查询和维护的噩梦。我选择选项5)或者6)从该列表中,可能已经通过列表解决了这个问题,但支持的内置postgres JSON/JSONB可能就足够了。
      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)
      );
      
      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;