Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql 与其他列一起索引JSONB键_Postgresql_Indexing_Database Design_Jsonb_Postgresql Performance - Fatal编程技术网

Postgresql 与其他列一起索引JSONB键

Postgresql 与其他列一起索引JSONB键,postgresql,indexing,database-design,jsonb,postgresql-performance,Postgresql,Indexing,Database Design,Jsonb,Postgresql Performance,为了在jsonb列中搜索特定键,我想在该列上创建一个索引 使用:Postgres 10.2 忽略一些不相关的列,我的表中有这些列(忽略一些不相关的列): 我需要根据以下内容进行搜索:位置,类型和标记ID。比如: where location = ? and type = 'cat' and (data ->> 'tagid') = ? 其他要点: 只有猫类型的动物才会有标签id,这是一个新的动物类型正在添加 与其他类型的动物相比,整张桌子上“猫”的数量更少 这张桌子很大,有数百万

为了在
jsonb
列中搜索特定键,我想在该列上创建一个索引

使用:Postgres 10.2

忽略一些不相关的列,我的表中有这些列(忽略一些不相关的列):

我需要根据以下内容进行搜索:
位置
类型
标记ID
。比如:

where location = ? and type = 'cat' and (data ->> 'tagid') = ?
其他要点:

  • 只有猫类型的动物才会有标签id,这是一个新的动物类型正在添加
  • 与其他类型的动物相比,整张桌子上“猫”的数量更少
  • 这张桌子很大,有数百万行,而且是分区的
如何确保搜索速度?我考虑过的备选方案:

  • 制作一个单独的表cats来存储:
    animal\u id
    location
    tagId
    (尽管无法将FK扩展到分区的父表)
  • 位置
    类型
    和jsonb键上创建索引
  • 创建一个新的(索引的)列
    tagId
    ——该列对于除猫以外的所有动物都为空
  • 我确实在表中的其他列上有一个索引,但是对于如何创建索引以使基于
    tagid
    的cat搜索快速,我有点困惑。有什么建议吗

    更新(忽略分区):

    (在分区表上测试)

    因此,我决定按照欧文的建议使用这个选项,并尝试创建一个索引

    CREATE INDEX ON animals_211 (location, ((data->>'tagid')::uuid)) WHERE  type = 'cat';
    
    并尝试对查询进行解释(使用分区表保持简单):

    从结果来看,它似乎没有使用创建的索引,而是进行顺序扫描:

    Seq Scan on animals_211  e  (cost=0.00..121.70 rows=1 width=327)                                                                                                        |
      Filter: ((location = 32341) AND ((type)::text = 'cat'::text) AND (((data ->> 'tagid'::text))::uuid = '5e54c1d9-3ea0-4bca-81d6-1000d90cc42c'::uuid
    
    更新2(不使用部分索引)

    不知何故,它似乎是部分索引,因为没有它-它似乎起作用:

    CREATE INDEX tag_id_index ON animals_211 (location, type, ((data->>'tagid')::uuid))
    
    当我执行解释计划时:

    Index Scan using tag_id_index on animals_211 e  (cost=0.28..8.30 rows=1 width=327)                                                                                         
      Index Cond: ((location = 32341) AND ((type)::text = 'cat'::text) AND (((data ->> 'tagid'::text))::uuid = '5e54c1d9-3ea0-4bca-81d6-1000d90cc42c'::uuid))
    
    基础(忽略分区) 根据你的三个“要点”,我建议对一个表达方式进行一次修改:

    创建动物索引((数据->>'tagid'))
    其中type='cat';
    
    用于避免对同一表进行并发写访问时出现锁定问题

    Postgres还为部分索引收集特定的统计数据,这有助于查询计划人员获得适当的估计注意如果在创建索引后立即测试索引,则需要手动运行
    ANALYZE
    (或
    VACUUM ANALYZE
    ),然后才能启动
    autovacuum
    。见:

    如果
    tagid
    确实是
    text
    以外的其他数据类型,则还可以强制转换表达式以进行更多优化。见:

    您的更新建议
    tagid
    存储UUID值。阅读:

    请考虑这个索引代替:

    创建动物索引(((数据->>'tagid')::uuid))--!
    其中type='cat';
    
    需要在
    (数据->>'tagid')::uuid
    周围添加一组括号,以使语法明确无误。
    和一个匹配的查询:

    选择*
    来自动物
    其中位置=32341
    和类型='cats'
    和(数据->>'tagid')::uuid='5e54c1d9-3ea0-4bca-81d6-1000d90cc42c';--!
    
    或者-取决于每个谓词的选择性以及可能的查询变体-包括
    位置
    ,使其成为多列索引:

    创建动物索引(位置,((数据->>'tagid')::uuid))
    其中type='cat';
    
    或者,如果您有查询,但没有对位置进行筛选,请先执行
    tagid
    。见:

    因为只有相对较少的行是“cat”类型,所以索引将相对较小,不包括“数百万行”的大部分。我们只需要猫的
    tagid
    索引就可以了。双赢

    如果可能,将json键
    data->>'tagid'
    作为专用列。(就像您认为的选项3.)在不适用的地方可以为null,null存储非常便宜。使存储和索引更便宜,但查询更简单

    分割 Postgres 10不支持分区表的父表上的索引。这是在Postgres 11中添加的。声明性分区从那时起得到了很大的改进。考虑升级到当前版本13或更高版本。

    还有“旧式”的选择。然后,您可以为CAT创建一个单独的分区,并在其中添加一列
    tagid

    对于声明式分区,分区必须具有与分区表完全相同的列集,而对于表继承,子表可能具有父表中不存在的额外列

    听起来很合适。但遗传已经不再受博士后的青睐,所以在这样做之前我会三思而后行

    无论是声明性还是继承性,如果在单独的分区中有所有的“cat”,那么非部分索引都会起作用,显然:

    在cats上创建索引(位置,((数据->>'tagid')::uuid));
    
    查询的目标可以是分区
    cats
    ,而不是父表:

    选择*
    来自猫
    其中位置=32341
    和(数据->>'tagid')::uuid='5e54c1d9-3ea0-4bca-81d6-1000d90cc42c';
    
    以父表为目标也应该有效。(对10级博士后不太清楚。)

    选择*
    来自动物
    其中type='cat'
    和位置=32341
    和(数据->>'tagid')::uuid='5e54c1d9-3ea0-4bca-81d6-1000d90cc42c';
    
    但要为此激活。手册:

    请注意,分区修剪仅由定义的约束驱动 隐式地通过分区键,而不是通过索引的存在。 因此,没有必要在键列上定义索引

    所有其他分区都应该被删减,然后你就可以删除了
    CREATE INDEX tag_id_index ON animals_211 (location, type, ((data->>'tagid')::uuid))
    
    Index Scan using tag_id_index on animals_211 e  (cost=0.28..8.30 rows=1 width=327)                                                                                         
      Index Cond: ((location = 32341) AND ((type)::text = 'cat'::text) AND (((data ->> 'tagid'::text))::uuid = '5e54c1d9-3ea0-4bca-81d6-1000d90cc42c'::uuid))