我应该选择 ->> 还是 @>

Should I prefer ->> or @>

在 JSONB 列的 postgreSQL 中,我可以 运行 两个具有相同 (?) 结果的查询。

查询 1:

SELECT * FROM a WHERE b->>'c' = 'lorem';

查询 2:

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

就性能和语义而言(也许还有一些我在这里没有看到的其他考虑因素),我应该使用什么查询来搜索 "the items from a where c is lorem"?

哪种解决方案对您来说更好是一个品味问题,您可以自己判断。它们在我看来几乎一样。

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

与 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

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

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

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

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

查询将受益于 (b) 上的 GIN 索引,但反之则不然。

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

如果您根本不想使用索引,那真的只是个人喜好问题。

旁注: 上面的解决方案在处理 NULLs 时略有不同:

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

将 select 行,并且 仅当 c 属性 具有 JSON null其中的价值,而

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

将 select 行, c 属性 根本没有在行中定义。

此外,

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

不会 select 任何行,因为 NULL 的标准兼容处理(表达式 (b ->> 'c') = NULL 总是评估为 NULL -- 或 UNKNOWNBOOLEAN 类型 -- 中,在 WHERE 谓词的上下文中总是 falsy)。