如何改进或索引postgresql的jsonb数组字段?
How to improve or index postgresql's jsonb array field?
我一般使用jsonb字段存储数组数据。
例如,我想存储客户的条形码信息,我将创建一个 table 像这样:
create table customers(fcustomerid bigint, fcodes jsonb);
一个客户有一行,所有条码信息都存储在其 fcodes 字段中,如下所示:
[
{
"barcode":"000000001",
"codeid":1,
"product":"Coca Cola",
"createdate":"2021-01-19",
"lottorry":true,
"lottdate":"2021-01-20",
"bonus":50
},
{
"barcode":"000000002",
"codeid":2,
"product":"Coca Cola",
"createdate":"2021-01-19",
"lottorry":false,
"lottdate":"",
"bonus":0
}
...
{
"barcode":"000500000",
"codeid":500000,
"product":"Pepsi Cola",
"createdate":"2021-01-19",
"lottorry":false,
"lottdate":"",
"bonus":0
}
]
jsonb 数组可能存储了数百万个具有相同结构的条码对象。也许这不是一个好主意,但你知道当我有成千上万的客户时,我可以将所有数据存储在一个 table 中,一个客户在这个 table 中有一行,它的所有数据存储在一个字段,看起来非常简洁易管理
对于这种应用场景,如何高效的插入或修改或查询数据?
我可以用jsonb_insert插入一个对象,就像:
update customers
set fcodes=jsonb_insert(fcodes,'{-1}','{...}'::jsonb)
where fcustomerid=999;
当我想修改某个对象时,发现有点困难,我应该先知道对象的索引,如果我使用增量键codeid作为数组索引,事情看起来很容易。我可以使用jsonb_modify,就像下面这样:
update customers
set fcodes=jsonb_set(fcodes,concat('{',(mycodeid-1)::text,',lottery}'),'true'::jsonb)
where fcustomerid=999;
但是如果我想用createdate或bonus或lottorry[=查询jsonb数组中的对象46=] 或 product,我应该使用 jsonpath 运算符。就像:
select jsonb_path_query_array(fcodes,'$ ? (product=="Pepsi Cola")'
from customer
where fcustomerid=999;
或喜欢:
select jsonb_path_query_array(fcodes,'$ ? (lottdate.datetime()>="2021-01-01".datetime() && lottdate.datetime()<="2021-01-31".datetime())'
from customer
where fcustomerid=999;
jsonb 索引看起来很有用,但它在不同行之间看起来很有用,我的操作主要在一行的一个 jsonb 字段中进行。
我很担心效率,对于存储在一行的一个 jsonb 字段中的数百万个对象,这是一个好主意吗?以及如何提高这种场景下的效率?特别是对于查询。
你的担心是对的。这么大的JSON,你永远不会有好的表现。
您的数据根本不需要 JSON。创建一个 table 存储单个条形码并具有对 customers
的外键引用。那么一切都会变得简单高效。
从本论坛的问题来看,在数据库中使用 JSON 几乎总是错误的选择。
我一般使用jsonb字段存储数组数据。 例如,我想存储客户的条形码信息,我将创建一个 table 像这样:
create table customers(fcustomerid bigint, fcodes jsonb);
一个客户有一行,所有条码信息都存储在其 fcodes 字段中,如下所示:
[
{
"barcode":"000000001",
"codeid":1,
"product":"Coca Cola",
"createdate":"2021-01-19",
"lottorry":true,
"lottdate":"2021-01-20",
"bonus":50
},
{
"barcode":"000000002",
"codeid":2,
"product":"Coca Cola",
"createdate":"2021-01-19",
"lottorry":false,
"lottdate":"",
"bonus":0
}
...
{
"barcode":"000500000",
"codeid":500000,
"product":"Pepsi Cola",
"createdate":"2021-01-19",
"lottorry":false,
"lottdate":"",
"bonus":0
}
]
jsonb 数组可能存储了数百万个具有相同结构的条码对象。也许这不是一个好主意,但你知道当我有成千上万的客户时,我可以将所有数据存储在一个 table 中,一个客户在这个 table 中有一行,它的所有数据存储在一个字段,看起来非常简洁易管理
对于这种应用场景,如何高效的插入或修改或查询数据?
我可以用jsonb_insert插入一个对象,就像:
update customers
set fcodes=jsonb_insert(fcodes,'{-1}','{...}'::jsonb)
where fcustomerid=999;
当我想修改某个对象时,发现有点困难,我应该先知道对象的索引,如果我使用增量键codeid作为数组索引,事情看起来很容易。我可以使用jsonb_modify,就像下面这样:
update customers
set fcodes=jsonb_set(fcodes,concat('{',(mycodeid-1)::text,',lottery}'),'true'::jsonb)
where fcustomerid=999;
但是如果我想用createdate或bonus或lottorry[=查询jsonb数组中的对象46=] 或 product,我应该使用 jsonpath 运算符。就像:
select jsonb_path_query_array(fcodes,'$ ? (product=="Pepsi Cola")'
from customer
where fcustomerid=999;
或喜欢:
select jsonb_path_query_array(fcodes,'$ ? (lottdate.datetime()>="2021-01-01".datetime() && lottdate.datetime()<="2021-01-31".datetime())'
from customer
where fcustomerid=999;
jsonb 索引看起来很有用,但它在不同行之间看起来很有用,我的操作主要在一行的一个 jsonb 字段中进行。
我很担心效率,对于存储在一行的一个 jsonb 字段中的数百万个对象,这是一个好主意吗?以及如何提高这种场景下的效率?特别是对于查询。
你的担心是对的。这么大的JSON,你永远不会有好的表现。
您的数据根本不需要 JSON。创建一个 table 存储单个条形码并具有对 customers
的外键引用。那么一切都会变得简单高效。
从本论坛的问题来看,在数据库中使用 JSON 几乎总是错误的选择。