我应该更喜欢 - >>或者@>

时间:2017-03-16 11:12:10

标签: 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"?

3 个答案:

答案 0 :(得分:8)

这取决于what indexes你有或想要添加(如果你想要使用索引)。以及您希望在jsonb类型列上执行的其他查询。

WHERE b->>'c' = 'lorem'

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

WHERE b @> '{"c": "lorem"}'

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

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

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

旁注:上述解决方案在处理NULL s时有点不同:

WHERE b @> '{"c": null}'

会选择行if,而只有 c属性中包含JSON null值,而

WHERE (b ->> 'c') IS NULL
如果c属性中包含JSON null值,

将选择行,根本未在行中定义c属性。

此外,

WHERE (b ->> 'c') = NULL

不会选择任何行,因为NULL s的标准合规处理(表达式(b ->> 'c') = NULL始终评估为NULL - 或UNKNOWN BOOLEAN类型 - 在WHERE谓词的上下文中始终为 falsy

答案 1 :(得分:1)

这是一个品味问题哪个解决方案对你来说更好,你在那里做法官。他们看起来和我一样。

说到性能,我建议你自己测试一下。 在PL / pgSQL中写一个DO语句,在循环中执行相同的操作100000次,然后使用psql命令\timing或类似的东西来查看它需要多长时间。多次重复测试以检查结果是否可重现。如果有的话,可能会在噪音中丢失差异。

答案 2 :(得分:1)

与Laurenz有同样的想法。尽管有顶级键值对的数量,它们似乎表现相同:

 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