查询中不使用表达式索引(正则表达式模式匹配)

Fab*_*ger 4 postgresql index regex

在我的PostgreSQL 12.8数据库中,我有一个相对简单的表the_table,其中有一列value类型为varchar

CREATE TABLE public.the_table (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    label character varying,
    value character varying,
    created_at timestamp without time zone NOT NULL,
    updated_at timestamp without time zone NOT NULL,
);
Run Code Online (Sandbox Code Playgroud)

我想查询具有格式为电子邮件地址的值的所有行。查询看起来像这样:SELECT * FROM the_table WHERE value ~ '^[a-zA-Z0-9.$%&*+/=?^_{|}~-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9]+$'

由于该表中有几百万行,我尝试通过添加匹配的表达式索引来加速此查询CREATE INDEX index_the_table_on_email_values ON the_table ((value ~ '^[a-zA-Z0-9.$%&*+/=?^_{|}~-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9]+$'));

不幸的是,查询计划程序不使用索引,而是对表执行完整扫描,这非常慢。

有人可以帮我修复索引或告诉我还有什么其他选择吗?我已经考虑过生成布尔列is_email。我可以向生成的列添加索引并直接查询它。但这对于原始问题来说似乎是一个奇怪的解决方法,应该可以通过匹配的索引来解决,对吗?

Erw*_*ter 6

公平地说,您对boolean表达式的索引基本上也有效。

要点是:如果“电子邮件”行占很大比例,则任何索引都不会(有很大)帮助 - 特殊情况除外。Postgres 通常会选择更快的顺序扫描。(我怀疑这就是你的情况。)
如果只有很少的“电子邮件”行,则部分索引会更有效,因为它首先排除了大多数行:

CREATE INDEX the_table_email_idx ON the_table ((true))
WHERE value ~ '^[a-zA-Z0-9.$%&*+/=?^_{|}~-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9]+$';
Run Code Online (Sandbox Code Playgroud)

(true)只是一个任意常数,因为没有明显的索引列。通常,您在“电子邮件过滤器”顶部有一个有用的索引列,可以替换该常量 - 使索引更加有用。有关的:

当然,生成列 is_email的想法也不错。然后,您可以使用该生成列上的条件创建部分索引。这有优点也有缺点。