使用Postgres 9.4 ,我想在搜索列中特定键时使用的json列上创建一个索引。
例如,我有一个带有json列'animals'的'farm'表。
animals列具有一般格式的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个动物,查询只需要很长时间来处理我的用例。像这样的索引是我能想到的加速查询的唯一方法,但也许还有另一种选择。
答案 0 :(得分:50)
您的其他两个索引无法正常工作,因为->>
operator会返回 text
,而您显然会考虑jsonb
个gin运算符类。请注意,您只提到json
,但实际上您需要jsonb
才能获得高级索引功能。
要制定出最佳的索引策略,您必须更准确地定义要覆盖的查询。你只对奶牛感兴趣吗?还是所有动物/所有标签?哪些运营商可能?您的JSON文档是否还包含非动物密钥?怎么办?是否要在索引中包含行(其中cows(或其他)根本没有出现在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
进行测试!