以下情况的最佳替代方案是什么?

时间:2016-12-22 13:03:34

标签: postgresql jsonb

我在Postgresql数据库中使用JSONB字段来存储以下文档。我拥有数千份文件。我需要使用此数据创建报告,但搜索速度非常慢。

如果我需要创建一份报告,说明一个月的新用户,我需要浏览整个文档,比较用户是在一个月而不在另一个月。

消息文档:

[{"recipient":1,"user":4,"created_at":"2016-11-10","content":"Duis aliquam convallis nunc.","is_sender_user":true},
{"recipient":1,"user":18,"created_at":"2016-12-10","content":"Proin eu mi.","is_sender_user":false},
{"recipient":1,"user":4,"created_at":"2016-11-20","content":"In hac habitasse platea dictumstm.","is_sender_user":true},
{"recipient":1,"user":20,"created_at":"2016-12-14","content":"Donec ut dolor.","is_sender_user":true},
{"recipient":1,"user":13,"created_at":"2016-12-06","content":"Nulla mollis molestie lorem. Quisque ut erat. Curabitur gravida nisi at nibh.","is_sender_user":true}]

最好创建一个User表并创建一个JSONB消息字段来存储您的消息。或者它的方式我可以使用JSONB查询创建我的报告?

2 个答案:

答案 0 :(得分:4)

您的邮件文档描述了用户之间的关系:发件人将内容传输到收件人。发件人可以发送许多邮件,收件人可能会收到许多邮件。这最好用关系结构表示,其中users表和消息表具有发送者和接收者的外键约束。

可以像你一样将所有内容放到JSONB字段中,但是有一些主要的缺点:查询性能受到影响,尽管Samuil Petrov提到这可以通过索引来改善;但更重要的是,没有任何东西阻止邮件拥有无效的用户或收件人ID。使用无模式JSONB字段可以简化开发,同时您仍然需要存储您需要存储的内容,但是一旦您知道需要什么,就应该由您的模式强制执行。

答案 1 :(得分:3)

正如Samuil Petrov所说,你可以在jsonb字段上创建索引,我建议在created_atuser

的月份部分创建索引
create INDEX td002_si3 ON testData002 (substring(doc->>'created',0,8),(doc->>'user'));

用这个查询

SELECT 
      substring(doc ->> 'created', 0, 8) AS m,
      ARRAY_AGG(DISTINCT doc ->> 'user')          AS users
    FROM testData002
    GROUP BY substring(doc ->> 'created', 0, 8)

将为您提供索引扫描中的每月用户

GroupAggregate  (cost=0.28..381.52 rows=3485 width=50)
  Group Key: ""substring""((doc ->> 'created'::text), 0, 8)
  ->  Index Scan using td002_si3 on testdata002  (cost=0.28..294.28 rows=3500 width=50)

生成的测试数据
create table testData002 as 
     select row_number() OVER () as id
           ,jsonb_build_object('created',dt::DATE
                              ,'user',(random()*1000)::INT) as doc 
       from generate_series(1,10),generate_series('2016-01-01'::TIMESTAMP,'2016-12-15'::TIMESTAMP,'1 day'::INTERVAL) as dt;