【问题标题】:Adding support for additional data types to Bloom Indexes向 Bloom Indexes 添加对其他数据类型的支持
【发布时间】:2022-01-01 03:17:52
【问题描述】:

Postgres 13.4.

我有一个设置,其中包含 uuid 在内的混合字段类型的 Bloom 索引可能非常有用。开箱即用,Bloom 扩展仅支持int4text。如何添加对其他类型的支持?

【问题讨论】:

  • 这样好多了!

标签: postgresql indexing operators bloom-filter


【解决方案1】:

根据 Laurenz Albe 的 cmets,我已将帖子改写为问答格式。

每隔几年,我都会从 Postgres Professional 的人员那里完成关于索引的精彩的十部分系列。我正在查看有关 Bloom 过滤器 (https://habr.com/en/company/postgrespro/blog/452968/) 的最后一篇文章,并发现了一个如何扩展对其他数据类型的支持的示例。它引起了我的注意,因为我以前没有弄清楚CREATE OPERATOR CLASS。我也没有找到在 Postgres 的 Bloom 索引的其他讨论中提到的这些细节。为了存档,我想我会写一些笔记,并希望能吸引一些额外的信息和/或更正。

Postgres 中的索引是....灵活的

Postgres 中的索引选项绝对是其十大功能之一。各种基本索引类型/框架和变体令人难以置信。不幸的是,pg_catalog 的索引相关部分非常密集。如果您有想要索引的内容,并且不支持该数据类型,那么您似乎可以使用CREATE OPERATOR CLASS 添加对其他类型的支持。在看到https://habr.com/en/company/postgrespro/blog/452968/ 的示例之前,我从来没有想过如何做到这一点。虽然这个示例和下面的代码专门针对 Bloom 过滤器索引,但我希望大部分机制可以转移到其他索引类型。

布隆过滤器

我今天不需要 Bloom 过滤器,并且可能永远想要一个。但是,老实说,它们非常酷*。在 Postgres 中了解一个很棒的功能,因为它们解决了一个您通常不会期望 RDBMS 有解决方案的问题。 (宽列,跨许多领域的随机搜索组合。)

我以前没有在 RDMBS 系统中看到布隆过滤器。我在分布式日志聚合系统中看到过它们,它们有助于减少来自远程位置或冷存储的不必要且昂贵的数据负载。 Postgres Bloom 过滤器与此不同。

我可能会很好地使用 Bloom 索引,因为我们有一个包含 13 个 UUID 列的宽表,这些列以任意数量的组合进行搜索,以及各种 int4 和其他数据。我喜欢提前试验这些东西,这样,如果出现问题,我已经有了可能的工具。而且,布隆过滤器不是 DBA 通常会立即想到的。但是,Bloom 索引是CREATE OPERATOR CLASS 的一个很好的示例。启动并运行它只需要三个步骤:

  1. 安装bloom 扩展(如果尚未安装)。

  2. 为感兴趣的数据类型和bloom 访问方法定义一个新的运算符类。这需要找到一个合适的散列函数。

  3. 使用新的运算符类创建新索引。

假设您已经安装了 bloom 扩展 (https://www.postgresql.org/docs/current/bloom.html),这里有一个小搜索来显示与 bloom 索引关联的运算符类:

select pg_am.amname,
       pg_opclass.opcintype::regtype,
       pg_opclass.opcname,
       pg_am.amhandler::regproc

from pg_opclass
left join pg_am on pg_am.oid = pg_opclass.opcmethod
where amname = 'bloom'
order by amname,opcname;

+--------+-----------+---------------+-----------+
| amname | opcintype | opcname       | amhandler |
+--------+-----------+---------------+-----------+
| bloom  | integer   | int4_ops      | blhandler |
| bloom  | text      | text_ops      | blhandler |
+--------+-----------+---------------+-----------+

所以,uuid 数据没有帮助。

添加操作符类

这是这个简单案例所需的代码:

CREATE OPERATOR CLASS uuid_ops
DEFAULT FOR TYPE uuid USING bloom AS
  OPERATOR  1  =(uuid,uuid),
  FUNCTION  1  uuid_hash;

我认为上面的代码或多或少意味着“OPERATOR strategy 1 EQUALITY hash”。我猜想将运算符类添加到具有更广泛运算符的索引类型会更复杂。布隆过滤器仅支持“可能存在/不存在”逻辑,因此只需要一个声明,以及要匹配的哈希函数。如果你再次运行前一个,它现在返回一个新操作符类的条目:

+--------+-----------+---------------+-----------+
| amname | opcintype | opcname       | amhandler |
+--------+-----------+---------------+-----------+
| bloom  | integer   | int4_ops      | blhandler |
| bloom  | text      | text_ops      | blhandler |
| bloom  | uuid      | uuid_ops      | blhandler |
+--------+-----------+---------------+-----------+

寻找合适的散列函数

不久前有人告诉我,虽然没有在文档中列出,但 Postgres 源代码包含大量特定于类型的哈希函数。为哈希索引实现了一整套类型特定的函数:

https://doxygen.postgresql.org/hashfunc_8c_source.html

我在那里没有看到uuid,但是这里实现了一个哈希:

https://github.com/postgres/postgres/blob/REL_13_STABLE/src/backend/utils/adt/uuid.c#L403

您只需要知道提供CREATE OPERATOR CLASS 的函数的名称,而不是它在源代码中的实现位置。

使用新的运算符类

有了这个,就可以在 uuid 数据上创建一个 Bloom 索引。这是一个好主意吗?不知道。我今天需要 Bloom 指数吗?不。但是我喜欢通过 Postgres 的功能来了解当我确实遇到合适的问题时可以使用什么。 Postgres 中的索引比我知道或见过的任何其他东西都要广泛得多……它们需要一些研究。下面是一个在 Bloom 索引上使用新运算符类的示例,该索引包括十个 uuid 字段,后跟三个 int4 字段。

create index analytic_work_bloom_idx on data.analytic_work
using bloom(
             id,
             hsys_id,
             facility_id,
             inv_id,
             user_id,
             activity_id,
             assembly_id,
             q_event_id,
             scan_id,
             scase_id,

             expected_count,
             actual_count,
             missing_count)

with (length=96,
           col1  = 7,
           col2  = 7,
           col3  = 7,
           col4  = 7,
           col5  = 7,
           col6  = 7,
           col7  = 7,
           col8  = 7,
           col9  = 7,
           col10 = 7,
           col11 = 7,
           col12 = 7,
           col13 = 7);

select pg_size_pretty(pg_total_relation_size('analytic_work_bloom_idx'));  --- Curious.

不要将上面的示例作为如何计算 Bloom 索引的正确签名长度和每列字节数的一个很好的示例。有很多文章解释了调整签名长度和每列字节数的机制、理论和建议方法。超过了我的工资等级。

粗略结果

我在示例数据库中有大约 600K+ 行,并添加了 Bloom 索引。结果应该是相当多变的,但就我而言,我发现:

  • 索引构建速度很好。
  • 13 个字段上的 bloom 索引大约是一个 uuid 字段上的 B 树的 4 倍。
  • Bloom 索引将随机多字段查询时间减半。您的 Millage 有所不同。

请补充和更正

我很高兴看到人们提供的任何额外信息或更正。

【讨论】:

    猜你喜欢
    • 2016-04-10
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多