为字段的数字比较编制jsonb索引
我定义了一个简单的表为字段的数字比较编制jsonb索引,json,postgresql,postgresql-9.4,jsonb,Json,Postgresql,Postgresql 9.4,Jsonb,我定义了一个简单的表 create table resources (id serial primary key, fields jsonb); 它包含具有键(从一个大集合中提取)和介于1和100之间的值的数据,如: id | fields --------+--------------
create table resources (id serial primary key, fields jsonb);
它包含具有键(从一个大集合中提取)和介于1和100之间的值的数据,如:
id | fields
--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 | {"tex": 23, "blair": 46, "cubic": 50, "raider": 57, "retard": 53, "hoariest": 78, "suturing": 25, "apostolic": 22, "unloosing": 37, "flagellated": 85}
2 | {"egoist": 75, "poshest": 0, "annually": 19, "baptists": 29, "bicepses": 10, "eugenics": 9, "idolizes": 8, "spengler": 60, "scuppering": 13, "cliffhangers": 37}
3 | {"entails": 27, "hideout": 22, "horsing": 98, "abortions": 88, "microsoft": 37, "spectrums": 26, "dilettante": 52, "ringmaster": 84, "floweriness": 72, "vivekananda": 24}
4 | {"wraps": 6, "polled": 68, "coccyges": 63, "internes": 93, "unburden": 61, "aggregate": 76, "cavernous": 98, "stylizing": 65, "vamoosing": 35, "unoriginal": 40}
5 | {"villon": 95, "monthly": 68, "puccini": 30, "samsung": 81, "branched": 33, "congeals": 6, "shriller": 47, "terracing": 27, "patriarchal": 86, "compassionately": 94}
我希望搜索其值(与特定键关联)大于某个基准值的条目。我可以通过以下方式实现这一点:
with exploded as (
select id, (jsonb_each_text(fields)).*
from resources)
select distinct id
from exploded
where key='polled' and value::integer>50;
。。。但当然,这并不使用索引,而是诉诸于表扫描。我想知道是否有:
您没有指定要使用的
索引的类型,也没有提供它的定义
对于jsonb
字段,典型的INDEX
将是一个索引,但在您的特定情况下,您需要实际比较轮询的键中包含的一些值
可能一个特定的索引
(虽然不是GIN
索引!)和一个,但我对此表示怀疑,它可能会变得相当麻烦,因为您至少需要一个双类型转换来获取整数值,还需要一个自定义的不可变的函数来实际执行CREATE INDEX
语句中的类型转换
在采用复杂的方法解决某些特定情况之前(如果需要使用不同的字段
键进行另一次比较怎么办?),您可以尝试优化当前查询,利用PostgreSQL 9.4的新功能和jsonb
处理功能。
结果是查询的运行速度应比当前查询快8倍:
SELECT r.id
FROM resources AS r,
LATERAL jsonb_to_record(r.fields) AS l(polled integer)
WHERE l.polled > 50;
编辑:
我做了一个快速测试,将我的评论中的想法付诸实践,即在实际比较值之前使用GIN索引
来限制行数,结果证明,即使在这种情况下,您也可以使用GIN索引
必须使用默认的操作符类创建索引jsonb_ops
(不是更轻、性能更高的jsonb_ops
):
现在,您可以利用索引,只需在查询中包含一个exist?
测试:
SELECT r.id
FROM resources AS r,
LATERAL jsonb_to_record(r.fields) AS l(polled integer)
WHERE r.fields ? 'polled' AND l.polled > 50;
现在查询的执行速度大约快了3倍(比第一个CTE版本快了20倍)。我已经测试了多达100万行,性能增益始终不变。
请记住,正如预期的那样,行数起着重要的作用:如果行数不到1K,索引就毫无用处,查询计划员可能不会使用它
另外,不要忘记与实际数据相比,jsonb_ops
索引可能会变得巨大。对于像您这样的数据样本,从1K到1M行不等,索引本身大约比表中的实际数据大170%,请自己检查:
SELECT pg_size_pretty(pg_total_relation_size('resources')) AS whole_table,
pg_size_pretty(pg_relation_size('resources')) AS data_only,
pg_size_pretty(pg_relation_size('resources_fields_idx')) AS gin_index_only;
为了让您了解一下,这个表大约有300K行,就像您的数据样本一样,大约250MB,由90MB的数据和160MB的索引组成!
就我个人而言,我会坚持(事实上我也坚持)不带索引的简单横向连接。您没有指定您希望使用哪种索引,也没有提供它的定义
对于jsonb
字段,典型的INDEX
将是一个索引,但在您的特定情况下,您需要实际比较轮询的键中包含的一些值
可能一个特定的索引
(虽然不是GIN
索引!)和一个,但我对此表示怀疑,它可能会变得相当麻烦,因为您至少需要一个双类型转换来获取整数值,还需要一个自定义的不可变的函数来实际执行CREATE INDEX
语句中的类型转换
在采用复杂的方法解决某些特定情况之前(如果需要使用不同的字段
键进行另一次比较怎么办?),您可以尝试优化当前查询,利用PostgreSQL 9.4的新功能和jsonb
处理功能。
结果是查询的运行速度应比当前查询快8倍:
SELECT r.id
FROM resources AS r,
LATERAL jsonb_to_record(r.fields) AS l(polled integer)
WHERE l.polled > 50;
编辑:
我做了一个快速测试,将我的评论中的想法付诸实践,即在实际比较值之前使用GIN索引
来限制行数,结果证明,即使在这种情况下,您也可以使用GIN索引
必须使用默认的操作符类创建索引jsonb_ops
(不是更轻、性能更高的jsonb_ops
):
现在,您可以利用索引,只需在查询中包含一个exist?
测试:
SELECT r.id
FROM resources AS r,
LATERAL jsonb_to_record(r.fields) AS l(polled integer)
WHERE r.fields ? 'polled' AND l.polled > 50;
现在查询的执行速度大约快了3倍(比第一个CTE版本快了20倍)。我已经测试了多达100万行,性能增益始终不变。
请记住,正如预期的那样,行数起着重要的作用:如果行数不到1K,索引就毫无用处,查询计划员可能不会使用它
另外,不要忘记与实际数据相比,jsonb_ops
索引可能会变得巨大。对于像您这样的数据样本,从1K到1M行不等,索引本身大约比表中的实际数据大170%,请自己检查:
SELECT pg_size_pretty(pg_total_relation_size('resources')) AS whole_table,
pg_size_pretty(pg_relation_size('resources')) AS data_only,
pg_size_pretty(pg_relation_size('resources_fields_idx')) AS gin_index_only;
为了让您了解一下,这个表大约有300K行,就像您的数据样本一样,大约250MB,由90MB的数据和160MB的索引组成!
就我个人而言,我会坚持(事实上也是这样)一个简单的横向连接
,没有索引。Re:“我期待什么样的索引”
:我不知道——这是我问题的关键:-),所以我不能真正给出“它的定义”。