Postgresql 我应该选择->&燃气轮机;或@>;

Postgresql 我应该选择->&燃气轮机;或@>;,postgresql,jsonb,postgresql-9.5,Postgresql,Jsonb,Postgresql 9.5,在JSONB列上的postgreSQL中,我可以使用相同的(?)结果运行两个查询 问题1: SELECT * FROM a WHERE b->>'c' = 'lorem'; 问题2: SELECT * FROM a WHERE b @> '{"c": "lorem"}'; 在性能和语义方面(可能还有其他一些我在这里没有看到的考虑因素),我应该使用什么查询来搜索“a中c是lorem”的项目?这是一个品味问题,你认为哪个解决方案更好,你是评判者。它们在我看来差不多 说到性能,我

在JSONB列上的postgreSQL中,我可以使用相同的(?)结果运行两个查询

问题1:

SELECT * FROM a WHERE b->>'c' = 'lorem';
问题2:

SELECT * FROM a WHERE b @> '{"c": "lorem"}';

在性能和语义方面(可能还有其他一些我在这里没有看到的考虑因素),我应该使用什么查询来搜索“a中
c
lorem
”的项目?

这是一个品味问题,你认为哪个解决方案更好,你是评判者。它们在我看来差不多

说到性能,我建议你自己测试一下。
在PL/pgSQL中编写一个
DO
语句,在循环中执行相同的操作100000次,然后使用
psql
命令
\timeing
或类似方法查看所需时间。重复测试几次,以检查结果是否可重复。这种差异很可能会在噪音中消失。

和劳伦斯的想法是一样的。尽管有许多顶级键值对,但它们的性能似乎是相同的:

 t=> do
t-> $$
t$> declare
t$>   _i int;
t$>   _j jsonb;
t$> begin
t$>   with n as (select generate_series(1,9999,1) g) select concat('{',string_agg(concat('"a',g,'":22'),','),',"c": "lorem"}')::jsonb into _j from n;
t$>   for _r in 1..999999 loop
t$>     select 1 into _i where _j @> '{"c": "lorem"}';
t$>   end loop;
t$> end;
t$> $$
t-> ;
DO
Time: 2406.016 ms
t=>
t=> do
t-> $$
t$> declare
t$>   _i int;
t$>   _j jsonb;
t$> begin
t$>   with n as (select generate_series(1,9999,1) g) select concat('{',string_agg(concat('"a',g,'":22'),','),',"c": "lorem"}')::jsonb into _j from n;
t$>   for _r in 1..999999 loop
t$>     select 1 into _i where _j->>'c' = 'lorem';
t$>   end loop;
t$> end;
t$> $$
t-> ;
DO
Time: 2799.750 ms
这取决于您是否拥有或想要添加索引(如果您想使用索引的话)。以及您希望在
jsonb
typed列上执行哪些其他查询

WHERE b->>'c' = 'lorem'
查询将受益于
(b->>'c')
表达式上的索引,而

查询将受益于
(b)
列上的GIN索引,但不是其他方式

第一种形式可能会产生更小、更有效的索引,但只适用于这种特殊情况。如果您还想查询
b
的其他属性,GIN索引可能会更有用

如果你根本不想使用索引,那真的只是品味的问题

旁注:当处理
NULL
s时,上述解决方案的工作原理略有不同:

WHERE b @> '{"c": null}'
如果
c
属性中有JSON
null
值,则将选择行,而

WHERE (b ->> 'c') IS NULL
如果
c
属性中有JSON
null
值,行中根本没有定义
c
属性,则将选择行

而且


不会选择任何行,因为对
NULL
s的标准兼容处理(表达式
(b->'c')=NULL
总是在
布尔类型--(在
WHERE
谓词的上下文中总是错误的)中计算为
NULL
--或
未知

BTW
(b->'c'))IS NULL
等于
(不是b?'c'或b@>“{c:NULL}”)
其中
运算符也由GIN索引支持。@Abelisto是的,完全正确。这只是一个笨拙的解决办法。但我怀疑很多人是否需要担心这样的边缘案例。我刚才提到这一点是因为这是这两种方法之间的唯一区别(如果OP不想使用索引)。
WHERE (b ->> 'c') IS NULL
WHERE (b ->> 'c') = NULL