JSON上的PostgreSQL索引

lnh*_*ell 34 postgresql json

使用Postgres 9.4,我想在json列上创建一个索引,该索引将在搜索列中的特定键时使用.

例如,我有一个带有json列'animals'的'farm'表.

animals列具有一般格式的json对象:

'{"cow": 2, "chicken": 11, "horse": 3}'
Run Code Online (Sandbox Code Playgroud)

我已经尝试了许多索引(单独):

(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'));
Run Code Online (Sandbox Code Playgroud)

我想运行如下查询:

SELECT * FROM farm WHERE (animal ->> 'cow') > 3;
Run Code Online (Sandbox Code Playgroud)

并让该查询使用索引.

当我运行此查询时:

SELECT * FROM farm WHERE (animal ->> 'cow') is null;
Run Code Online (Sandbox Code Playgroud)

然后(1)索引起作用,但我不能让任何索引适用于不等式.

这样的指数可能吗?

农场表只包含约5000个农场,但其中一些包含100个动物,查询对我的用例来说只需要太长时间.像这样的索引是我能想到的加速查询的唯一方法,但也许还有另一种选择.

Erw*_*ter 63

你的其他两个索引不会仅仅因为->>操作符返回text而起作用,而你明显有jsonbgin操作符类.请注意,您只需提及json,但实际上您需要jsonb高级索引功能.

要制定出最佳的索引策略,您必须更详细地定义要覆盖的查询.你只对奶牛感兴趣吗?还是所有动物/所有标签?哪些运营商可能?您的JSON文档是否还包含非动物密钥?怎么办?是否要在索引中包含行(其中cows(或其他)根本没有出现在JSON文档中?

假设:

  • 我们只对第一级筑巢的奶牛感兴趣.
  • 该值始终有效integer.
  • 我们对没有奶牛的行感兴趣.

我建议使用功能性btree索引,就像你已经拥有的那样,但是将值转换为整数.我不认为您希望比较评估为text(其中'2'大于'1111').

CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int));  -- !
Run Code Online (Sandbox Code Playgroud)

转换速记需要额外的括号集,以使索引表达式的语法明确无误.

在查询中使用相同的表达式使Postgres意识到索引适用:

SELECT * FROM farm WHERE (animal ->> 'cow')::int > 3;
Run Code Online (Sandbox Code Playgroud)

如果您需要更通用的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;
Run Code Online (Sandbox Code Playgroud)

等等.

您可能必须将索引条件添加到查询中:

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

似乎多余,但可能是必要的.测试ANALYZE!