Postgresql 有效地分组许多字段,包括大文本和jsonb

Postgresql 有效地分组许多字段,包括大文本和jsonb,postgresql,jsonb,Postgresql,Jsonb,提前道歉。。。冗长的问题 假设我有一个表table_x,其中有20个字段: table_x_id (identity pk) int1 int... int8 text1 text... text8 jsonb1 jsonb2 现在假设我想在表x中保持对分组数据的快速访问(例如,字段int1、int2、text1\u id、text2\u id和jsonb1)。称之为报告1。在提出这个问题时,数据并没有真正发挥重要作用,但这里有一个来自报告1的虚构片段: +------------------

提前道歉。。。冗长的问题

假设我有一个表
table_x
,其中有20个字段:

table_x_id (identity pk)
int1
int...
int8
text1
text...
text8
jsonb1
jsonb2
现在假设我想在
表x
中保持对分组数据的快速访问(例如,字段int1、int2、text1\u id、text2\u id和jsonb1)。称之为
报告1
。在提出这个问题时,数据并没有真正发挥重要作用,但这里有一个来自
报告1
的虚构片段:

+-----------------------------------------------------------------------+
| int1value int2value text1value text2value jsonb1->item1 jsonb1->item2 |
+-----------------------------------------------------------------------+
|                                                       (table_x_id) 12 |
|                                                       (table_x_id) 20 |
|                                                       (table_x_id) 34 |
+-----------------------------------------------------------------------+
现在假设我有三个或更多这样的报告需求,并且每个报告都涉及到对
table_x
中的许多(但不是全部)字段进行分组

每个文本字段可以很容易地达到,比如说,1000个字符,而jsonb字段虽然不大,但只会增加问题

挑战:加快报告分组。

为了加快分组操作并减小表的行大小,我将唯一的文本字段值(确实有很多重叠)拆分为一个单独的
text\u表

现在
表x
是:

table_x_id (identity pk)
int1
int...
int8
text1_id (fk lookup)
text..._id (fk lookup)
text8_id (fk lookup)
jsonb1
jsonb2
table_x_id (identity pk)
int1
int...
int8
text1_id (lookup)
text..._id (lookup)
text8_id (lookup)
jsonb1
jsonb2
hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1)
hash2_bytea (based on int3, int7, text3_id, jsonb1 and jsonb2)
hash3_bytea (based on int2, int5, text1_id and jsonb2)
jsonb_id (identity pk)
jsonb (unique jsonb)
table_x_id (identity pk)
int1
int...
int8
text1_id (fk lookup)
text..._id (fk lookup)
text8_id (fk lookup)
jsonb1_id (fk lookup)
jsonb2_id (fk lookup)
hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1_id )
hash2_bytea (based on int3, int7, text3_id, jsonb1_id  and jsonb2_id )
hash3_bytea (based on int2, int5, text1_id and jsonb2_id )
jsonb_child_id (pk identity)
jsonb_id (fk to jsonb_table)
key_lookup_id (fk lookup)
value_lookup_id (fk lookup)
在分组方面,我当时考虑在insert/update触发器中使用digest()调用,在
表_x
本身中维护相关列的散列。(其思想是将分组中的所有相关字段转换为字符串,将它们连接在一起,并对结果字符串运行哈希。)

现在
表x
是:

table_x_id (identity pk)
int1
int...
int8
text1_id (fk lookup)
text..._id (fk lookup)
text8_id (fk lookup)
jsonb1
jsonb2
table_x_id (identity pk)
int1
int...
int8
text1_id (lookup)
text..._id (lookup)
text8_id (lookup)
jsonb1
jsonb2
hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1)
hash2_bytea (based on int3, int7, text3_id, jsonb1 and jsonb2)
hash3_bytea (based on int2, int5, text1_id and jsonb2)
jsonb_id (identity pk)
jsonb (unique jsonb)
table_x_id (identity pk)
int1
int...
int8
text1_id (fk lookup)
text..._id (fk lookup)
text8_id (fk lookup)
jsonb1_id (fk lookup)
jsonb2_id (fk lookup)
hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1_id )
hash2_bytea (based on int3, int7, text3_id, jsonb1_id  and jsonb2_id )
hash3_bytea (based on int2, int5, text1_id and jsonb2_id )
jsonb_child_id (pk identity)
jsonb_id (fk to jsonb_table)
key_lookup_id (fk lookup)
value_lookup_id (fk lookup)
报告现在需要更多的查找,但这很快,现在我只需要按hash1_bytea进行分组,以实现相同的
report 1
输出

恐惧:不同行中的等效jsonb字段在按其jsonb::text表示进行比较时可能不等效。据我所知,这些担心似乎是有道理的。

但是,如果我不能以确定的方式将jsonb值转换为文本,我的“表内散列字段”解决方案就会崩溃

然后,我决定在一个单独的
jsonb_表
中维护jsonb值,其中我保证任何一行都有一个唯一的jsonb对象

jsonb_表是:

table_x_id (identity pk)
int1
int...
int8
text1_id (fk lookup)
text..._id (fk lookup)
text8_id (fk lookup)
jsonb1
jsonb2
table_x_id (identity pk)
int1
int...
int8
text1_id (lookup)
text..._id (lookup)
text8_id (lookup)
jsonb1
jsonb2
hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1)
hash2_bytea (based on int3, int7, text3_id, jsonb1 and jsonb2)
hash3_bytea (based on int2, int5, text1_id and jsonb2)
jsonb_id (identity pk)
jsonb (unique jsonb)
table_x_id (identity pk)
int1
int...
int8
text1_id (fk lookup)
text..._id (fk lookup)
text8_id (fk lookup)
jsonb1_id (fk lookup)
jsonb2_id (fk lookup)
hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1_id )
hash2_bytea (based on int3, int7, text3_id, jsonb1_id  and jsonb2_id )
hash3_bytea (based on int2, int5, text1_id and jsonb2_id )
jsonb_child_id (pk identity)
jsonb_id (fk to jsonb_table)
key_lookup_id (fk lookup)
value_lookup_id (fk lookup)
对于任何唯一的jsonb对象(在文本中表示时忽略其中对象的顺序),现在在
jsonb_表
中只有一行表示它

现在
表x
是:

table_x_id (identity pk)
int1
int...
int8
text1_id (fk lookup)
text..._id (fk lookup)
text8_id (fk lookup)
jsonb1
jsonb2
table_x_id (identity pk)
int1
int...
int8
text1_id (lookup)
text..._id (lookup)
text8_id (lookup)
jsonb1
jsonb2
hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1)
hash2_bytea (based on int3, int7, text3_id, jsonb1 and jsonb2)
hash3_bytea (based on int2, int5, text1_id and jsonb2)
jsonb_id (identity pk)
jsonb (unique jsonb)
table_x_id (identity pk)
int1
int...
int8
text1_id (fk lookup)
text..._id (fk lookup)
text8_id (fk lookup)
jsonb1_id (fk lookup)
jsonb2_id (fk lookup)
hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1_id )
hash2_bytea (based on int3, int7, text3_id, jsonb1_id  and jsonb2_id )
hash3_bytea (based on int2, int5, text1_id and jsonb2_id )
jsonb_child_id (pk identity)
jsonb_id (fk to jsonb_table)
key_lookup_id (fk lookup)
value_lookup_id (fk lookup)
是的,维护
text_表
jsonb_表
是一件麻烦事,但这是可行的,而且
table_x
现在看起来非常有效,能够快速维护多个散列

看来我已经完成了快速,准确的分组对多种口味的许多领域分组

在这一点上,我要提出两个问题:

  • 我的方法是否合理且设计相对完善?还是有更好的方法来实现我的目标

  • jsonb1和jsonb2中的json实际上只是一个使用频率较低的特殊键值对数组,但是jsonb1和jsonb2中的数据需要引用完整性,数据保存在规范化的关系表中。在这种情况下,创建一个
    jsonb_child_表
    会是一个坏主意吗

  • jsonb_child_表是:

    table_x_id (identity pk)
    int1
    int...
    int8
    text1_id (fk lookup)
    text..._id (fk lookup)
    text8_id (fk lookup)
    jsonb1
    jsonb2
    
    table_x_id (identity pk)
    int1
    int...
    int8
    text1_id (lookup)
    text..._id (lookup)
    text8_id (lookup)
    jsonb1
    jsonb2
    hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1)
    hash2_bytea (based on int3, int7, text3_id, jsonb1 and jsonb2)
    hash3_bytea (based on int2, int5, text1_id and jsonb2)
    
    jsonb_id (identity pk)
    jsonb (unique jsonb)
    
    table_x_id (identity pk)
    int1
    int...
    int8
    text1_id (fk lookup)
    text..._id (fk lookup)
    text8_id (fk lookup)
    jsonb1_id (fk lookup)
    jsonb2_id (fk lookup)
    hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1_id )
    hash2_bytea (based on int3, int7, text3_id, jsonb1_id  and jsonb2_id )
    hash3_bytea (based on int2, int5, text1_id and jsonb2_id )
    
    jsonb_child_id (pk identity)
    jsonb_id (fk to jsonb_table)
    key_lookup_id (fk lookup)
    value_lookup_id (fk lookup)
    
    同样,要确保
    jsonb_child_表
    中的记录是
    jsonb_表
    中jsonb字段的正确分支,也是一件麻烦事,但通过这种方式,我可以:

    • 快速维护之前讨论过的所有分组信息
    • 保证良好的引用完整性
    • 使用
      jsonb_child_表
      中的字段报告jsonb1(例如),这些字段是通过元数据(通过使用
      key_lookup_id
      的sql连接)排序的(例如),而不是存储在jsonb1本身中
    最后一点似乎与我在其他地方读到的内容相呼应,所以。。。在jsonb中维护键值数组需要重新思考。。。如果您想要确保对排序、引用完整性和更快地获取数据,那么jsonb可能是一个糟糕的选择。然而,在我的例子中,维护一个jsonb“header”表(提供一个外键标识字段)允许快速分组不同的值对集合(在
    table_x
    )。因此,我看到了在jsonb(便于分组)和真实表(用于RI和更快、更干净的报告)中维护相同数据的好处

    是的,这第二个问题本身值得提出另一个SO问题,但整个问题似乎是相互关联的,所以我在一篇(对不起)长篇文章中介绍了这一切


    提前感谢您的反馈

    如果您提供一些示例输入数据和基于该数据的预期输出,您的问题将更容易理解。有关如何创建美观的表格的一些提示,请参阅。感谢您提供的好链接。我已经根据您的建议更改了我的示例数据。如果您提供一些示例输入数据和基于该数据的预期输出,您的问题将更容易理解。有关如何创建美观的表格的一些提示,请参阅。感谢您提供的好链接。我已经按照你的建议更改了我的样本数据。