对索引位集进行大批量更新的最佳方法

时间:2017-11-21 03:53:56

标签: postgresql apache-spark database-performance jsonb

此问题的环境是AWS RDS上的PostgreSQL 9.6.5。

问题是关于包含以下逻辑数据模型的3亿行的表的最佳模式设计和批量更新策略:

  • id:主键,最多40个字符的字符串
  • code:整数1-999
  • year:整年
  • flags:每个与名称关联的变量号(1000+),随时间添加的新标志。理想情况下,标志应被视为具有三个值:缺席(null),开启(true / 1)和关闭(false / 0 )。有可能以额外的更新(见下文)为代价,将标志视为一个简单的位(开或关,不存在)。 "在"值通常非常稀疏:< 1/1000。

查询通常涉及一个或多个标志(按名称)是否存在的布尔表达式,偶尔也会涉及codeyear

数据通过Apache Spark批量更新,即,更新可以表示为平面文件,例如,以COPY格式,或作为SQL操作。任何时候只有一个更新处于活动状态。 codeyear的更新非常罕见。对标志的更新会影响每次更新1-5%的行(3-15百万行)。更新行可以包含所有标志及其值,只包括" on"要更新的标志或仅更改其值的标志。在前一种情况下,Spark需要查询数据以获取标志的当前值。

更新期间会有一个小的读取负载。

问题是关于支持查询的最佳模式和相关更新策略。如上所述进行更新。

迄今为止的一些研究评论:

  • 使用1,000多个布尔列将创建一个非常有效的行表示,但除了一些DDL复杂性之外,还需要1,000多个索引。

  • 如果有一种方法可以索引单个位,那么位串会很棒。而且,它们没有提供表示缺席标志的好方法。使用此方法需要在标志名称和位ID之间维护查找表。如果需要,合并更新可以与||一起使用,但是,鉴于PostgreSQL的MVCC,仅更新标志而不是替换整行似乎没什么好处。

  • JSONB字段提供索引。他们还提供null代表,但这需要付出代价:所有标志都是"关闭"需要明确设置,这将使字段非常大。如果我们忽略null表示,JSONB字段将相对较小。为了进一步缩小它们,我们可以使用短的1-3字符字段名称和查找表。相同的评论:与位串合并。

  • tsvector / tsquery:对此数据类型没有经验,但理论上,它似乎是一组" on"的完全代表。按名称标记。必须使用查找表将标志名称映射到令牌,并附加要求以确保不会因为词干而发生冲突。

1 个答案:

答案 0 :(得分:1)

不要将标志存放在主表中。

假设主表名为data,请定义如下内容:

CREATE TABLE flag_names (
   id smallint PRIMARY KEY,
   name text NOT NULL
);

CREATE TABLE flag (
   flagname_id smallint NOT NULL REFERENCES flag_names(id),
   data_id text NOT NULL REFERENCES data(id),
   value boolean NOT NULL,
   PRIMARY KEY (flagname_id, data_id)
);

如果创建了新标志,请在flag_names中插入新行。

如果某个标志设置为TRUEFALSE,请在flag表格中插入或更新一行。

使用flag加入data以测试是否设置了某个标记。