在JSONB列上的postgreSQL中,我可以使用相同的(?)结果运行两个查询。
查询1:
SELECT * FROM a WHERE b->>'c' = 'lorem';
查询2:
SELECT * FROM a WHERE b @> '{"c": "lorem"}';
在性能和语义方面(可能还有一些其他考虑因素我不会在这里看到),我应该使用什么查询来搜索来自a
c
的项目。是lorem
"?
答案 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