在Postgres中有效搜索整个1级嵌套JSONB

时间:2016-04-27 16:55:20

标签: postgresql lookup jsonb postgresql-9.5

让我们说我们需要检查一个jsonb列是否包含任何值(非嵌套,只有第一级)的子字符串匹配的特定值。

如何有效地优化查询以搜索值的整个​​JSONB列(这意味着每个键)?

对jasonb数据类型执行ILIKE %val%是否有一些很好的替代方法?

jsonb_each_text(jsonb_column) ILIKE '%val%'

作为示例,请考虑以下数据:

SELECT 
  '{
   "col1": "somevalue", 
   "col2": 5.5, 
   "col3": 2016-01-01, 
   "col4": "othervalue", 
   "col5": "yet_another_value"
  }'::JSONB

如果需要在包含jsonb列中不同行的不同键配置的记录中搜索模式%val%,您将如何优化查询?

我意识到使用前后%符号进行搜索效率低下,因此寻找更好的方法,但很难找到一个。此外,显式索引json列中的所有字段不是一个选项,因为它们对于每种类型的记录都有所不同,并且会创建一大组索引(并非每行都有相同的键集)。

问题

是否有更好的替代方法可以将每个键值对提取到文本并执行ILIKE / POSIX搜索?

1 个答案:

答案 0 :(得分:0)

如果您知道只需要查询几个已知密钥,那么您只需索引这些表达式即可。

这是一个太简单但自我解释的例子:

create table foo as SELECT '{"col1": "somevalue", "col2": 5.5, "col3": "2016-01-01", "col4": "othervalue", "col5": "yet_another_value"}'::JSONB as bar;

create index pickfoo1 on foo ((bar #>> '{col1}'));
create index pickfoo2 on foo ((bar #>> '{col2}'));

这是基本的想法,即使它对 ilike 查询没有用,但你可以做更多的事情(取决于你的需要)。

例如:如果只需要不区分大小写的匹配,则只需执行以下操作:

-- Create index over lowered value:
create index pickfoo1 on foo (lower(bar #>> '{col1}'));
create index pickfoo2 on foo (lower(bar #>> '{col2}'));

-- Check that it matches:
select * from foo where lower(bar #>> '{col1}') = lower('soMEvaLUe');
  

注意:这只是一个示例:如果您对上一个选择执行解释,您会看到postgres实际执行了   顺序扫描而不是使用索引。但这是因为我们是   用一行测试一个表,这不常见。但   我相信你可以用更大的表来测试它; - )

如果firt wilcard没有出现在字符串的开头,那么即使是像查询这样的查询也应该受益于索引(但这不是jsonb的问题,而是一个问题btree索引自己)。

如果您需要优化以下查询:

select * from foo where bar #>> '{col1}' ilike '%MEvaL%';

...那么你应该考虑使用GIN或GIST索引。