2016-03-18 51 views
14

使用Postgres 9.4,我想在json列上创建一个索引,当在列内的特定键上进行搜索时将使用这个索引。JSON上的PostgreSQL索引

例如,我有一个'农场'表json列'动物'。

动物列具有通用格式的JSON对象:

'{"cow": 2, "chicken": 11, "horse": 3}' 

我已经尝试了一些指标(单独):

(1) create INDEX animal_index ON farm ((animal ->> 'cow')); 
(2) create INDEX animal_index ON farm using gin ((animal ->> 'cow')); 
(3) create INDEX animal_index ON farm using gist ((animal ->> 'cow')); 

我想运行之类的查询:

SELECT * FROM farm WHERE (animal ->> 'cow') > 3; 

并让该查询使用该索引。

当我运行此查询:

SELECT * FROM farm WHERE (animal ->> 'cow') is null; 

则(1)指数的作品,但我不能让任何指数为不平等的工作。

这样的索引可能吗?

农场桌只包含〜5000个农场,但其中一些包含100多个动物,并且查询对我的用例来说太长。像这样的索引是我能想到的用于加速查询的唯一方法,但也许还有另一种选择。

回答

29

你的其他两个指标将无法正常工作,只是因为->> operator回报text,而你明明有jsonb杜松子酒算子类的想法。请注意,您只提到json,但您实际需要jsonb以获得高级索引功能。

为了制定出最佳索引策略,您必须更密切地定义要涵盖哪些查询。你只对牛有兴趣吗?或所有的动物/所有标签?哪些运营商可能?你的JSON文件是否也包含非动物密钥?如何处理这些?你是否想在索引中包含行(或其他什么)不在JSON文档中显示的行?

假设:

  • 我们只是在奶牛在嵌套的第一级感兴趣。
  • 该值始终是有效的integer
  • 我们对没有奶牛的行感兴趣。

我建议一个函数btree索引,很像你已经有的,但将值转换为整数。我不认为你想将比较评估为text(其中'2'大于'1111')。

CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int)); -- ! 

的额外的括号是必需的投速记,以便为索引表达式明确的语法。

使用在查询相同的表达,使Postgres的实现指标是适用的:

SELECT * FROM farm WHERE (animal ->> 'cow')::int > 3; 

如果你需要一个更通用jsonb指数,考虑:

对于已知的,静态的,微不足道的数量的动物(如哟ü评论),我建议喜欢的部分索引:

CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int)) 
WHERE (animal ->> 'cow') IS NOT NULL; 

CREATE INDEX animal_index ON farm (((animal ->> 'chicken')::int)) 
WHERE (animal ->> 'chicken') IS NOT NULL; 

等等

您可能需要索引条件添加到查询:

SELECT * FROM farm 
WHERE (animal ->> 'cow')::int > 3 
AND (animal ->> 'cow') IS NOT NULL; 

看起来是多余的,但可能是必要的。用ANALYZE进行测试!

+0

谢谢!精彩的回答。我只对第一级感兴趣。该值始终是一个整数。不过,我对其他一些动物感兴趣。简单地复制我感兴趣的每只动物的这个索引是否有意义? – lnhubbell

+0

@lnhubbell:对于已知的,静态的,微不足道的动物数量,这应该是最简单和最有效的解决方案。不过,我会明确地让它们成为部分索引。见上面的附录。 –