询问
您的表定义丢失。假设:
CREATE TABLE configuration (
config_id serial PRIMARY KEY
, config jsonb NOT NULL
);
要找到value
给定的 a 及其行oid
和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
连接。相比:
2) 获得 3 列的表的最快方法是什么oid
,instance
以及value.
我想使用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
jsonb_ops
A和GIN 索引的技术区别在于jsonb_path_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'
。必须注意将所有谓词应用于同一数组元素。您可以将其与第一个查询结合使用:
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
瞧。
特殊指标
如果您的表很大,则索引大小可能是一个决定因素。您可以将此特殊解决方案的性能与功能索引进行比较:
此函数从给定值中提取oid-instance组合的 Postgres 数组: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包含运算符@>
。我不希望有很大的不同,但我会很感兴趣哪个更快。
类似于此相关答案中的第一个解决方案(但更专业):
旁白:
- 我不会
oid
用作列名,因为它也用于 Postgres 的内部目的。
- 如果可能的话,我会使用一个没有 JSON 的普通规范化表。