使用 Postgres 9.4,我想在 json 列上创建一个索引,该索引将在搜索列中的特定键时使用。
例如,我有一个带有 json 列“动物”的“农场”表。
animals 列有一般格式的 json 对象:
'{"cow": 2, "chicken": 11, "horse": 3}'
我已经尝试了一些索引(分别):
create INDEX animal_index ON farm ((animal ->> 'cow'));
create INDEX animal_index ON farm using gin ((animal ->> 'cow'));
使用 gist ((animal ->> 'cow')) 在农场创建 INDEX animal_index;
我想运行如下查询:
SELECT * FROM farm WHERE (animal ->> 'cow') > 3;
并让该查询使用索引。
当我运行这个查询时:
SELECT * FROM farm WHERE (animal ->> 'cow') is null;
那么 (1) 索引有效,但我无法让任何索引为不等式工作。
这样的索引可能吗?
农场表仅包含约 5000 个农场,但其中一些包含 100 只动物,对于我的用例而言,查询时间太长。像这样的索引是我能想到的加快查询速度的唯一方法,但也许还有另一种选择。
最佳答案
您的其他两个索引将无法正常工作,因为 ->>
operator返回 text
,而您显然已经记住了 jsonb
gin 运算符类。请注意,您只提到了 json
,但实际上需要 jsonb
用于高级索引功能。
要制定最佳索引策略,您必须更仔细地定义要覆盖的查询。你只对牛感兴趣吗?还是所有动物/所有标签?哪些运算符是可能的?您的 JSON 文档是否还包含非动物键?这些怎么办?您想在索引中包含牛(或其他)根本没有出现在 JSON 文档中的行吗?
假设:
整数
。我建议使用功能性 btree 索引,就像您已经拥有的那样,但将值转换为 integer
。我认为您不希望将比较评估为 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
进行测试!
https://stackoverflow.com/questions/36075918/