- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
用于搜索 jsonb
中的特定键列,我想在该列上创建索引。
使用:Postgres 10.2
忽略一些不相关的列,我有表 animals
包含这些列(省略一些不相关的列):
animalid PK number
location (text)
type (text)
name (text)
data (jsonb) for eg: {"age": 2, "tagid": 11 }
我需要根据:location
进行搜索, type
和tagId
。喜欢:
where location = ? and type = 'cat' and (data ->> 'tagid') = ?
其他要点:
如何确保搜索速度快?我考虑过的选项:
animal_id
, location
, tagId
(尽管无法FK到分区父表)location
上创建索引, type
和 jsonb key 。tagId
- 对于除猫之外的所有动物来说,这都是 null。我确实在表上的其他列上有一个索引 - 但对如何创建索引以基于 tagid
搜索猫有点困惑快速地。有什么建议吗?
更新(忽略分区):
(在分区表上测试)
所以我决定采用 Erwin 建议的选项并尝试创建索引
CREATE INDEX ON animals_211 (location, ((data->>'tagid')::uuid)) WHERE type = 'cat';
并尝试对查询进行解释(使用分区表以保持简单):
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
更新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 还收集部分索引的特定统计信息,这有助于查询规划器获得适当的估计。 请注意,如果您在创建后立即在 autovacuum
之前测试索引,则需要手动运行 ANALYZE
(或 VACUUM ANALYZE
) > 可以启动。请参阅:
如果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.)在不适用的情况下可以为空,空存储非常便宜。使存储和索引更便宜,并且查询更简单。
Postgres 10 不支持分区表的父表上的索引。这是在 Postgres 11 中添加的。此后声明性分区得到了很大改进。很多。考虑升级到当前版本 13 或更高版本。
还有“旧式”选项partitioning with inheritance 。然后,您可以为猫建立一个单独的分区,并仅在其中添加一个附加列tagid
。 The manual :
For declarative partitioning, partitions must have exactly the same set of columns as the partitioned table, whereas with table inheritance, child tables may have extra columns not present in the parent.
听起来非常合适。但是继承已经不再受到 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为了那个原因。手册:
Note that partition pruning is driven only by the constraints definedimplicitly by the partition keys, not by the presence of indexes.Therefore it isn't necessary to define indexes on the key columns.
应修剪所有其他分区,然后您应该仅对 cats
分区进行索引扫描...
关于postgresql - 结合其他列对 JSONB 键建立索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65974129/
我在 php 方面遇到了一个小问题,我发现很难用语言来解释。我有一个包含键值的关联数组。我想制作一个函数(或者如果已经有一个函数),它将一个数组作为输入并删除重复项,但两种方式都是如此。 例如: 在我
我有一个在系统托盘中运行的应用程序,是否可以允许用户通过 C# 中的 Windows 键 + 键 恢复该应用程序? 谢谢 最佳答案 是的,使用 Windows API。我认为 Windows 键与 C
我正在使用 Waterline通过 Sails 查询 MySQL 数据库。我找到了 2 种方法。 不知道哪个更好? 顺便问一下,如何处理这两种情况的错误? 1. Model.findOne().whe
我正在尝试测试是否按下了 Alt 键。 我的支票类似于: private void ProcessCmdKey(Keys keyData) { if (keyData == Keys.Alt) {
我正在使用 Selenium WebDriver 和 Ruby 进行自动化测试。我需要点击一个按钮。我无法通过 id 或 css 或 xpath 获取按钮元素,因为按钮是透明的。我想使用 Tab 和
我是 IntelliJ 的新手,我看到一个启动提示说,“任何工具窗口中的 ⎋ 键都会将焦点移动到编辑器。”但是,我不知道⎋键是什么。我一直在编程很长时间。我的键盘上可能有一个我多年来一直错过的键吗?
我使用 OMDB API 创建了一个电影搜索页面。我遇到的问题是,如果我搜索一部包含多个单词的电影,此 API 会出错,因为 API 的 URL 必须在 URL 中的每个单词之间有 + 键。所以我想知
我已经用 Elasticsearch 玩了大约一天了,所以我非常陌生。我正在尝试 POST/import 一个简单的文件: { "compression" : "none", "com
enter image description here 在此示例中,要记录带有“title”和“director”键的属性值,使用 obj[key]。因为我们已经处于对象的执行上下文中:在本例中是电
我是新开类。 我使用新的电子邮件 ID 和密码在 openshift 上创建了一个项目。让我们称之为 firstApp 。我做了 rhc 设置和我的 ssh key 与我的项目相关联。 我的 frie
当我使用 Jackson 反序列化 json 字符串时,我通常不想创建所有 bean 类的属性,而且我只需要一些 json 字符串的字段,其他字段我不需要。所以我经常只在我需要的 java 类 bea
我想编写一个带有 keys/keys* 的规范,但能够内联值规范,但不支持 by design ,我明白了其背后的原因。然而,有时,本地图存在特定上下文时,您确实希望(或者只是通过遗留或第三方)键和值
my %fruit_colors = ("apple", "red", "banana", "yellow"); my @fruits = keys %fruit_colors; my @colors
我正在使用 vb.net 2008 和 DataGridView。我正在寻找允许我将 enter 键移动到右侧的下一列而不是在保持在同一列时向下移动一行的代码。 最佳答案 如果您正在确认编辑,只需移动
我刚刚开始学习编码,我遇到了这个我无法理解的问题。 “我们将添加的第二个函数称为搜索,它将以名字作为参数。它将尝试将收到的名字与我们 friend 联系人列表中的任何名字相匹配。如果它找到匹配项,就会
我已经在 Python 中运行了下面的代码,以从文本文件中生成单词列表及其计数。我该如何从“Frequency_list”变量中过滤掉计数为 1 的单词? 另外,如何将底部的打印语句循环导出到CSV
我正在尝试 XSLT 中的查找表示例,但无法使其正常工作
是否可以在 Javascript/Typescript 中编写一个将参数名称/键作为字符串返回的函数? function foo(arg) {...} let user = new User(); f
我正在尝试创建一个带有键/值的对象,但是当我看到该对象时,键没有正确填充.. 我希望键是 - 0,1,2,3 但它显示“索引”作为键。 > categories = ["09/07/2016 00:0
将 Android Studio 从 1.5 升级到 2.0 后,模拟器(现在版本为 25.1.1,我在其上配置了模拟硬件键盘)不再将 [Esc] 键识别为等同于 [Back] 按钮。 如何恢复这个有
我是一名优秀的程序员,十分优秀!