为字段的数字比较编制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;
。。。但当然,这并不使用索引,而是诉诸于表扫描。我想知道是否有:

  • 查询“polled”>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:“我期待什么样的
    索引”
    :我不知道——这是我问题的关键:-),所以我不能真正给出“它的定义”。