我有一个json数组,其中包含大约1000个结构为“ oid:aaa,instance:bbb,value:ccc”的元素。
{"_id": 37637070 , "data": [{"oid": "11.5.15.1.4", "value": "1", "instance": "1.1.4"} , {"oid": "11.5.15.1.9", "value": "17", "instance": "1.1.4"} , {"oid": "12.5.15.1.5", "value": "0.0.0.0", "instance": "0"}]}
oid并且instance每个json数组都是唯一的。如果可以更改结构,可以将格式更改为 key:value :
oid
instance
{"11.5.15.1.4-1.1.4":"1", "11.5.15.1.9-1.1.4": "17", "12.5.15.1.5-0": "0.0.0.0"}
但是,如果我需要保留旧结构
oid从阵列中获取特定信息的最快方法是什么?
什么是得到一个表的3列最快的方式oid,instance和value。甚至更好的是将oid + instance作为列标题的数据透视表。
value
对于2。我尝试了以下操作,但是在大桌子上速度很慢:
select * from ( select a->>'oid' oid, a->>'instance' instance, a->>'value' value1, id from ( select jsonb_array_elements(config#>'{data}') a, id from configuration ) b ) c where oid = '1.3.6.1.4.1.7352.3.10.2.5.35.3' and instance = '0' and value1 <> '1';
您的表定义丢失。假设:
CREATE TABLE configuration ( config_id serial PRIMARY KEY , config jsonb NOT NULL );
查找value给定oid和的a 及其行instance:
SELECT c.config_id, d->>'value' AS value FROM configuration c , jsonb_array_elements(config->'data') d -- default col name is "value" WHERE d->>'oid' = '1.3.6.1.4.1.7352.3.10.2.5.35.3' AND d->>'instance' = '0' AND d->>'value' <> '1'
那是一个隐式LATERAL联接。比较:
LATERAL
2)什么是得到一个表的3列最快的方法oid,instance和value.
value.
我想使用 jsonb_populate_recordset() ,那么您可以在表定义中提供数据类型。假设text所有:
jsonb_populate_recordset()
text
CREATE TEMP TABLE data_pattern (oid text, value text, instance text);
也可以是持久化(非临时)表。这仅适用于当前会话。然后:
SELECT c.config_id, d.* FROM configuration c , jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d
就这样。第一个查询重写:
SELECT c.config_id, d.* FROM configuration c , jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d WHERE d.oid = '1.3.6.1.4.1.7352.3.10.2.5.35.3' AND d.instance = '0' AND d.value <> '1';
但这比第一个查询 要慢 。具有更大表的性能的关键是索引支持:
您可以轻松地为问题中建议的标准化(已翻译)表或替代布局编制索引。索引 当前的布局 不是很明显,但是也可以。为了获得最佳性能,我建议data对jsonb_path_ops运算符类的键仅使用功能索引。每个文档:
data
jsonb_path_ops
a jsonb_ops和jsonb_path_opsGIN索引之间的技术区别在于,前者为数据中的每个键和值创建独立的索引项,而后者仅为数据中的每个值创建索引项。
jsonb_ops
这 应该 对性能产生 奇迹 :
CREATE INDEX configuration_my_idx ON configuration USING gin ((config->'data') jsonb_path_ops);
可能希望只有一个完全匹配的JSON数组元素才能起作用,例如:
SELECT * FROM configuration WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3" , "instance": "0", "value": "1234"}]';
注意JSON数组符号(与 包封[])所提供的值,这是所需要的。
[]
但是带有 键子集的 数组元素也可以工作:
SELECT * FROM configuration WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3" , "instance": "0"}]'
困难的部分是合并您看似毫无疑问的添加谓词value <> '1'。必须注意将所有谓词应用于 同一 数组元素。您可以将其与第一个查询结合使用:
value <> '1'
SELECT c.*, d->>'value' AS value FROM configuration c , jsonb_array_elements(config->'data') d WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3", "instance": "0"}]' AND d->>'oid' = '1.3.6.1.4.1.7352.3.10.2.5.35.3' -- must be repeated AND d->>'instance' = '0' -- must be repeated AND d->>'value' <> '1' -- here we can rule out
Voilá。
如果表很大,则索引大小可能是决定因素。您可以将此特殊解决方案的性能与功能索引进行比较:
此函数从给定值提取Postgres oid-instance 组合数组jsonb:
jsonb
CREATE OR REPLACE FUNCTION f_config_json2arr(_j jsonb) RETURNS text[] LANGUAGE sql IMMUTABLE AS $func$ SELECT ARRAY( SELECT (elem->>'oid') || '-' || (elem->>'instance') FROM jsonb_array_elements(_j) elem ) $func$
我们可以基于此构建功能索引:
CREATE INDEX configuration_conrfig_special_idx ON configuration USING gin (f_config_json2arr(config->'data'));
并基于此查询:
SELECT * FROM configuration WHERE f_config_json2arr(config->'data') @> '{1.3.6.1.4.1.7352.3.10.2.5.35.3-0}'::text[]
这个想法是索引应该小得多,因为它只存储组合值而没有键。的 阵列 容纳操作者 @>本身应该执行类似于jsonb容纳操作者 @>。我希望不会有太大的区别,但是我会很感兴趣,这更快。
@>
类似于此相关答案中的第一个解决方案(但更具体):