INSERT INTO jsonb_test (data)
SELECT row_to_json(x.*)::jsonb
FROM (SELECT i AS bla,
ARRAY[i, i+1, i+2] AS foo,
ARRAY[('v' || i::text, i), ('v' || (i * 10)::text, i)] AS bar
FROM generate_series(1,100000) t(i)
) x;
让我们在那里找到一些东西(版本 1):
SELECT * FROM jsonb_test WHERE data @> '{"bla": 545}'::jsonb;
执行计划看起来像
Seq Scan on jsonb_test (cost=0.00..7604.89 rows=369 width=36) (actual time=0.425..47.600 rows=1 loops=1)
Filter: (data @> '{"bla": 545}'::jsonb)
Rows Removed by Filter: 99999
Buffers: shared hit=2997 dirtied=676
Planning time: 0.078 ms
Execution time: 47.692 ms
如果我对您建议的其他版本(版本 2-> )执行相同操作(操作员从更改->>为我认为您的意思):
SELECT * FROM jsonb_test WHERE data ->> 'bla' = '545';
我有一个计划
Seq Scan on jsonb_test (cost=0.00..8526.47 rows=1843 width=36) (actual time=0.613..34.657 rows=1 loops=1)
Filter: ((data ->> 'bla'::text) = '545'::text)
Rows Removed by Filter: 99999
Buffers: shared hit=2997
Planning time: 0.116 ms
Execution time: 34.727 ms
我创建了一个小测试来检查这个:
然后插入一些生成的数据:
让我们在那里找到一些东西(版本 1):
执行计划看起来像
如果我对您建议的其他版本(版本 2
->
)执行相同操作(操作员从更改->>
为我认为您的意思):我有一个计划
反复运行它们,我发现执行时间之间没有显着差异。难怪 - 这里的昂贵操作是顺序扫描,而两种不同的过滤条件在这方面应该没有太大的不同。
现在我添加一个 GIN 索引
data
:现在执行查询时,版本 2与上述相同,而版本 1有一个新计划:
这已经表明这两个版本并不完全等效——
jsonb
列上的 GIN 索引仅支持其中一个(版本 1)。可以定义另一个索引来帮助版本 2:
现在版本 2提供以下内容:
在这个实验中,给定正确的索引,我没有看到两者之间的巨大性能差异。但是,您应该考虑以下事项:
通常说 BTree 索引比 GIN 索引维护成本更低(意味着表上的数据更改具有更小的开销)。通过阅读,情况并非总是如此——您必须在自己的数据集上测试这些解决方案。例如,我无法判断一组非常复杂的
jsonb
值是否会更喜欢这个或那个。笔记:
json(b)
要了解运营商的异同,官方文档是一个很好的来源。