我应该如何在 Postgres 中索引 UUID?

sud*_*udo 39 postgresql index uuid

我是 PostgreSQL 的新手,一般来说对数据库有点陌生。我们应该如何在 Postgres 中索引UUID值,是否有既定的方法?我分为使用散列和使用特里树,除非已经有内置的东西可以自动使用。无论我使用什么,都将处理大量数据。

SP-GiST 运算符族“text_ops”使用树索引。因为 UUID 很长而且非常不同,所以即使我只会进行完整匹配搜索,这些听起来也很吸引人。

还有一个哈希选项。散列是 O(1),当然除了相等我不需要做任何比较,但是因为 UUID 很长,我担心从它们生成散列会浪费很多时间。

或者这是否过于依赖系统和使用细节?

在大多数情况下,我宁愿使用bigserial,但有人告诉我为此使用uuid。我们需要uuid,因为我们可能有多个服务器使用不同的数据库,因此不能保证我们将拥有唯一的 bigint。我们可以为每个服务器使用不同的序列(和种子),但它仍然不如 UUID 灵活。例如,如果不转换 ID 及其引用,我们将无法将数据库条目从一台服务器迁移到另一台服务器。

Cra*_*ger 47

使用 PostgreSQL 的内置uuid数据类型,并在其上创建一个常规的 b-tree 索引。

没有必要做任何特别的事情。这将产生最佳索引,并且还将uuid以当前实用的紧凑形式存储该字段。

(PostgreSQL 10 版本之前的哈希索引不是崩溃安全的,而且实际上是一个历史遗留物,无论如何都不会比 b 树表现得更好。避免使用它们。在 PostgreSQL 10 上,它们已经被设置为崩溃安全的,并且有一些进行了性能改进,因此您可能希望考虑它们。)

如果由于某种原因您不能使用该uuid类型,您通常会在文本表示上创建一个 b 树,或者最好bytea是 uuid的表示。

  • 虽然关于“hash”索引与“b-tree”的声明是普遍持有的信念,但我认为引用此类声明的来源会有所帮助。 (2认同)
  • 从 PostgreSQL 10 开始,`hash` 索引现在是崩溃安全的。也就是说,`hash` 索引只能与`=` 一起使用,所以如果你需要任何其他操作符,`b-tree` 仍然是可取的。 (2认同)
  • 几年后,根据我的经验,`hash` 并没有比 `b-tree` 快多少,即使在 Postgres 10 中也是如此。但是由于哈希索引占用的磁盘空间比 b-tree 少得多,所以它可能会更快在大索引成为问题的设置中,我觉得这对我来说并非如此。好吧,我现在会密切关注,因为我实际上可以在 v10 中安全地使用它们。 (2认同)

Naj*_*jib 7

BRIN 指数?如果您使用基于时间(版本 1)的 UUID,则会生成它们,以便它们的值增加。在这种情况下,BRIN 是合适的。

https://www.postgresql.org/docs/9.5/brin-intro.html

BRIN 代表块范围索引。BRIN 设计用于处理非常大的表,其中某些列与它们在表中的物理位置有一些自然的相关性。阿块范围是一组属于在表中物理相邻的页; 对于每个块范围,索引存储了一些摘要信息。例如,存储商店销售订单的表可能有一个日期列,每个订单都在该列上放置,并且大多数情况下,较早订单的条目也会出现在表中的较早位置;存储邮政编码列的表可能将城市的所有代码自然组合在一起。

BRIN 索引可以通过常规位图索引扫描来满足查询,如果索引存储的摘要信息与查询条件一致,将返回每个范围内所有页面中的所有元组。查询执行器负责重新检查这些元组并丢弃那些与查询条件不匹配的元组——换句话说,这些索引是有损的。由于 BRIN 索引非常小,因此与顺序扫描相比,扫描索引增加的开销很小,但可以避免扫描已知不包含匹配元组的大部分表。

BRIN 索引将存储的特定数据,以及索引能够满足的特定查询,取决于为索引的每一列选择的运算符类。例如,具有线性排序顺序的数据类型可以具有存储每个块范围内的最小值和最大值的运算符类;几何类型可能会存储块范围内所有对象的边界框。

块范围的大小在索引创建时由 pages_per_range 存储参数确定。索引条目的数量将等于页中关系的大小除以 pages_per_range 的选定值。因此,数字越小,索引越大(因为需要存储更多的索引条目),但同时存储的摘要数据可以更精确,在索引扫描时可以跳过更多的数据块。

非常适合庞大且“主要”有序的数据。

有关一些基准测试,请参阅此帖子:

https://www.percona.com/blog/2019/07/16/brin-index-for-postgresql-dont-forget-the-benefits/

他们生成了一个 1.3 GB 的自然排序数据表(时间戳加注)。然后他们在这个数据库上生成了一个 BRIN 索引(pages_per_range = 32)和一个 B-Tree 索引。然后他们比较了 SELECT 执行时间和索引的大小。他们得到了什么:

B树:

规划时间:22.225 毫秒执行时间:2.657毫秒

公共| testtab_date_idx | 索引 | postgres | 测试表| 171 MB

布林:

规划时间:0.272 毫秒执行时间:87.703 毫秒

公共| testtab_date_brin_idx | 索引 | postgres | 测试表| 64 KB

同时没有索引它将是:

规划时间:0.296 毫秒执行时间:1766.454 毫秒

只是为了给人一种命令的感觉。

需要进一步讨论的是两者的INSERT后索引更新的复杂性。对于 BRIN,它是 O(1),因为您在内存上的下一个可用空间上顺序写入并相应地创建新的 BRIN 条目,但是对于我们熟知的 B-Tree,它是 O(logN) ( B-Trees ) (树越高,需要的时间越长)。