结合其他列索引 JSONB 键 基础知识忽略分区分区

如何解决结合其他列索引 JSONB 键 基础知识忽略分区分区

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

使用:Postgres 10.2

忽略一些不相关的列,我的表 animals 包含这些列(省略了一些不相关的列):

animalid PK number
location (text)
type (text)
name (text)
data (jsonb) for eg: {"age": 2,"tagid": 11 }

我需要根据:locationtypetagId 进行搜索。喜欢:

where location = ? and type = 'cat' and (data ->> 'tagid') = ?

其他要点:

  • 只有猫类型的动物才会有标签 ID,这是现在添加的新动物类型。
  • 与其他类型的动物相比,整个表格中“猫”的数量会更少。
  • 该表很大,有数百万行 - 并且已分区。

如何确保搜索速度快?我考虑过的选项:

  1. 制作一个单独的表cats来存储:animal_idlocationtagId(虽然FK到分区的父表是不可能的)
  2. locationtype 和 jsonb 键上创建索引。
  3. 创建一个新的(索引)列 tagId - 对于除猫之外的所有动物,该列都为空。

我确实在表的其他列上有一个索引 - 但对如何创建索引以快速基于 tagid 搜索猫有点困惑。有什么建议吗?

UPDATE(忽略分区):

(在分区表上测试)

所以我决定采用 Erwin 建议的选项并尝试创建索引

CREATE INDEX ON animals_211 (location,((data->>'tagid')::uuid)) WHERE  type = 'cat';

并在查询上尝试了 EXPLAIN(使用分区表以保持简单):

explain select * from animals_211 a
where a.location  = 32341
and a.type  = 'cat'
and (data->>'tagid')::uuid = '5e54c1d9-3ea0-4bca-81d6-1000d90cc42c'

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

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

UPDATE 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))

解决方法

基础知识(忽略分区)

根据您的三个“重要点”,我建议在表达式上使用 partial index

CREATE INDEX ON animals ((data->>'tagid'))
WHERE  type = 'cat';

使用 CREATE INDEX CONCURRENTLY ... 可避免对同一表进行并发写入访问的锁定问题。

Postgres 还为部分索引收集特定的统计信息,这有助于查询规划器获得适当的估计。 注意,如果您在创建索引后在 ANALYZE 启动之前立即测试它,您需要手动运行 VACUUM ANALYZE(或 autovacuum)。请参阅:

如果 tagid 确实是除 text 之外的其他数据类型,您还可以强制转换表达式以进一步优化。见:

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

所以考虑这个索引:

CREATE INDEX ON animals (((data->>'tagid')::uuid))  -- !
WHERE  type = 'cat';

需要在 (data->>'tagid')::uuid 周围加上一组额外的括号才能使语法无歧义。
还有一个匹配的查询:

SELECT *
FROM   animals
WHERE  location = 32341
AND    type = 'cats'
AND    (data->>'tagid')::uuid = '5e54c1d9-3ea0-4bca-81d6-1000d90cc42c';  -- !

或者 - 取决于每个谓词的选择性以及查询的哪些变体是可能的 - 包括 location 以使其成为多列索引:

CREATE INDEX ON animals (location,((data->>'tagid')::uuid))
WHERE  type = 'cat';

或者 tagid 如果您有没有过滤位置的查询。见:

由于只有相对较少的行属于“cat”类型,因此索引将相对较小,不包括“数百万行”的大部分。我们只需要 tagid 上的索引让猫开始。双赢。

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

分区

Postgres 10 不支持分区表的父表上的索引。这是在 Postgres 11 中添加的。自那以后,声明式分区得到了很多的改进。考虑升级到当前版本 13 或更高版本。

还有“旧式”partitioning with inheritance 选项。然后你可以有一个单独的猫分区,只有在那里有一个额外的列 tagidThe manual

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

听起来很合适。但是继承已经不受 Postgres 的青睐,所以我在做之前会三思。

无论哪种方式 - 无论是声明式还是继承式 - 如果您在单独的分区中拥有所有“猫”,显然非部分索引可以完成这项工作:

CREATE INDEX ON cats (location,((data->>'tagid')::uuid));

并且查询可以针对分区 cats 而不是父表:

SELECT *
FROM   cats
WHERE  location = 32341
AND    (data->>'tagid')::uuid = '5e54c1d9-3ea0-4bca-81d6-1000d90cc42c';

定位父表也应该有效。 (不确定 Postgres 10。)

SELECT *
FROM   animals
WHERE  type = 'cat'
AND    location = 32341
AND    (data->>'tagid')::uuid = '5e54c1d9-3ea0-4bca-81d6-1000d90cc42c';

但是为此激活 partition pruning。说明书:

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

应该修剪所有其他分区,然后您应该只对 cats 分区进行索引扫描...

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)> insert overwrite table dwd_trade_cart_add_inc > select data.id, > data.user_id, > data.course_id, > date_format(
错误1 hive (edu)> insert into huanhuan values(1,'haoge'); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive> show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 <configuration> <property> <name>yarn.nodemanager.res