Pet*_*ris 33 postgresql json postgresql-9.3
目前的Postgresql版本已经为JSON内容引入了各种功能,但我担心的是我是否真的应该使用它们 - 我的意思是,还没有"最佳实践"已经确定哪些有效,哪些无效,或者至少我可以'找到它.
我有一个具体的例子 - 我有一个关于对象的表,除其他外,它包含该对象的备用名称列表.所有这些数据也将包含在JSON列中以供检索.例如(跳过所有其他不相关的字段).
create table stuff (id serial primary key, data json);
insert into stuff(data) values('{"AltNames":["Name1","Name2","Name3"]}')
Run Code Online (Sandbox Code Playgroud)
我将需要一些查询形式"列出其中一个altnames为'foobar'的所有对象." 预期的表大小大约为几百万条记录.可以使用Postgres JSON查询,也可以将其编入索引(例如,用于在JSON数组中查找元素的索引).但是,它应该以这种方式完成,还是不建议使用反常的解决方法?
当然,经典的替代方法是为该一对多关系添加一个附加表,其中包含主表的名称和外键; 这种表现很好理解.但是,这有其自身的缺点,因为它意味着该表与JSON之间的数据重复(可能存在完整性风险); 或者在每次请求时动态创建JSON返回数据,这会有自己的性能损失.
Den*_*rdy 25
我将需要一些查询形式"列出其中一个altnames为'foobar'的所有对象." 预期的表大小大约为几百万条记录.可以使用Postgres JSON查询,也可以将其编入索引(例如,在JSON数组中查找元素索引).但是,它应该以这种方式完成,还是不建议使用反常的解决方法?
它可以这样做,但这并不意味着你应该这样做.从某种意义上说,最佳实践已经有很好的文档记录(参见例如使用hstore vs使用XML与使用EAV而不是使用单独的表)和新的数据类型,对于所有意图和实际目的(除了验证和语法),没有什么不同来自先前的非结构化或半结构化选项.
换句话说,这是与新化妆相同的老猪.
JSON提供了使用反向搜索树索引的能力,与hstore,数组类型和tsvector相同.它们工作正常,但请记住,它们主要用于提取按距离排序的邻域中的点(想想几何类型),而不是按字典顺序提取值列表.
为了说明,请采用罗马答案概述的两个计划:
回到你的问题:如果你使用Postgres表作为巨型JSON商店,那么杂乱和超大的倒置树索引确实会提高你的应用程序的性能.但它们也不是银弹,在处理瓶颈时它们不会让你达到适当的关系设计.
最后,底线与决定使用hstore或EAV时的底线没有什么不同:
Rom*_*kar 20
我说值得一试.我已经创建了一些测试(100000条记录,JSON数组中的~10个元素)并检查它是如何工作的:
create table test1 (id serial primary key, data json);
create table test1_altnames (id int, name text);
create or replace function array_from_json(_j json)
returns text[] as
$func$
select array_agg(x.elem::text)
from json_array_elements(_j) as x(elem)
$func$
language sql immutable;
with cte as (
select
(random() * 100000)::int as grp, (random() * 1000000)::int as name
from generate_series(1, 1000000)
), cte2 as (
select
array_agg(Name) as "AltNames"
from cte
group by grp
)
insert into test1 (data)
select row_to_json(t)
from cte2 as t
insert into test1_altnames (id, name)
select id, json_array_elements(data->'AltNames')::text
from test1
create index ix_test1 on test1 using gin(array_from_json(data->'AltNames'));
create index ix_test1_altnames on test1_altnames (name);
Run Code Online (Sandbox Code Playgroud)
查询JSON(我的机器上30ms):
select * from test1 where '{489147}' <@ array_from_json(data->'AltNames');
"Bitmap Heap Scan on test1 (cost=224.13..1551.41 rows=500 width=36)"
" Recheck Cond: ('{489147}'::text[] <@ array_from_json((data -> 'AltNames'::text)))"
" -> Bitmap Index Scan on ix_test1 (cost=0.00..224.00 rows=500 width=0)"
" Index Cond: ('{489147}'::text[] <@ array_from_json((data -> 'AltNames'::text)))"
Run Code Online (Sandbox Code Playgroud)
查询表名称(我的机器上15ms):
select * from test1 as t where t.id in (select tt.id from test1_altnames as tt where tt.name = '489147');
"Nested Loop (cost=12.76..20.80 rows=2 width=36)"
" -> HashAggregate (cost=12.46..12.47 rows=1 width=4)"
" -> Index Scan using ix_test1_altnames on test1_altnames tt (cost=0.42..12.46 rows=2 width=4)"
" Index Cond: (name = '489147'::text)"
" -> Index Scan using test1_pkey on test1 t (cost=0.29..8.31 rows=1 width=36)"
" Index Cond: (id = tt.id)"
Run Code Online (Sandbox Code Playgroud)
另外我要注意,使用names(test1_altnames
)将行插入/删除到表中会有一些成本,所以它比仅选择行要复杂一些.我个人喜欢用JSON解决方案.
归档时间: |
|
查看次数: |
14727 次 |
最近记录: |