我在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查询创建我的报告?
答案 0 :(得分:4)
您的邮件文档描述了用户之间的关系:发件人将内容传输到收件人。发件人可以发送许多邮件,收件人可能会收到许多邮件。这最好用关系结构表示,其中users表和消息表具有发送者和接收者的外键约束。
可以像你一样将所有内容放到JSONB字段中,但是有一些主要的缺点:查询性能受到影响,尽管Samuil Petrov提到这可以通过索引来改善;但更重要的是,没有任何东西阻止邮件拥有无效的用户或收件人ID。使用无模式JSONB字段可以简化开发,同时您仍然需要存储您需要存储的内容,但是一旦您知道需要什么,就应该由您的模式强制执行。
答案 1 :(得分:3)
正如Samuil Petrov所说,你可以在jsonb字段上创建索引,我建议在created_at
和user
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;