gpt4 book ai didi

sql - 加快嵌套在 jsonb 对象数组中的键值的范围测试

转载 作者:行者123 更新时间:2023-11-29 13:15:35 26 4
gpt4 key购买 nike

假设我有以下 parents 表:

create table parents (
id integer not null constraint parents_pkey primary key,
name text not null,
children jsonb not null
);

其中 children 是一个具有以下结构的 json 数组:

[
{
"name": "child1",
"age": 10
},
{
"name": "child2",
"age": 12
}
]

例如,我需要获取所有 child 年龄在 10 到 12 岁之间的 parent 。

我创建以下查询:

select distinct
p.*
from
parents p, jsonb_array_elements(p.children) c
where
(c->>'age')::int between 10 and 12;

parents 表很大(例如 1M 条记录)时,它运行良好但速度很慢。我尝试在 children 字段上使用“ Gin ”索引,但这没有帮助。

那么有没有办法加快这样的查询呢?或者也许有另一种解决方案可以针对 嵌套 json 数组 中的字段 进行查询/索引?

查询计划:

Unique  (cost=1793091.18..1803091.18 rows=1000000 width=306) (actual time=4070.866..5106.998 rows=399947 loops=1)
-> Sort (cost=1793091.18..1795591.18 rows=1000000 width=306) (actual time=4070.864..4836.241 rows=497313 loops=1)
Sort Key: p.id, p.children, p.name
Sort Method: external merge Disk: 186040kB
-> Gather (cost=1000.00..1406321.34 rows=1000000 width=306) (actual time=0.892..1354.147 rows=497313 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Nested Loop (cost=0.00..1305321.34 rows=416667 width=306) (actual time=0.162..1794.134 rows=165771 loops=3)
-> Parallel Seq Scan on parents p (cost=0.00..51153.67 rows=416667 width=306) (actual time=0.075..239.786 rows=333333 loops=3)
-> Function Scan on jsonb_array_elements c (cost=0.00..3.00 rows=1 width=0) (actual time=0.004..0.004 rows=0 loops=1000000)
Filter: ((((value ->> 'age'::text))::integer >= 10) AND (((value ->> 'age'::text))::integer <= 12))
Rows Removed by Filter: 3
Planning time: 0.218 ms
Execution time: 5140.277 ms

最佳答案

第一个直接措施是使查询速度更快:

SELECT *
FROM parents p
WHERE EXISTS (
SELECT FROM jsonb_array_elements(p.children) c
WHERE (c->>'age')::int BETWEEN 10 AND 12
);

EXISTS 半连接避免了当多个数组对象匹配时中间表中的行重复 - 以及在外部查询中对 DISTINCT ON 的需要。但这只是稍快一些。

核心问题是您要测试一个整数值范围,而existing jsonb operators不提供此类功能。

有多种解决方法。不知道这些,这是解决给定示例的“智能”解决方案。诀窍是将范围拆分为不同的值并使用 jsonb 包含运算符 @>:

SELECT *
FROM parents p
WHERE (p.children @> '[{"age": 10}]'
OR p.children @> '[{"age": 11}]'
OR p.children @> '[{"age": 12}]');

jsonb_path_ops GIN 索引支持:

CREATE INDEX parents_children_gin_idx ON parents USING gin (children jsonb_path_ops);

但是如果您的范围超过一手整数值,您将需要更通用的东西。 总是,最佳解决方案取决于完整的情况:数据分布、值频率、查询中的典型范围、可能的 NULL 值?、行大小、读/写模式、每个 em> jsonb 值有一个或多个匹配的 age 键? ...

具有专门的、非常快速的索引的相关答案:

相关:

关于sql - 加快嵌套在 jsonb 对象数组中的键值的范围测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49532773/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com