Postgres 函数索引不能与正则表达式一起正常工作

Kar*_*rew 5 postgresql index regular-expression functions

我有这个 Postgres 功能。它强制文本为小写,所有空值变为空字符串,以便我更干净地执行搜索不匹配的内容等:

CREATE OR REPLACE FUNCTION magic_text(txt text) RETURNS text
IMMUTABLE PARALLEL SAFE
LANGUAGE SQL AS $$
  SELECT lower(coalesce(txt,''))
$$;
Run Code Online (Sandbox Code Playgroud)

这个函数在许多不同的查询类型中被大量使用,所以我为它创建了所有种类的文本索引:

CREATE INDEX index_magic_cards_on_oracle_text_magic 
ON magic_cards 
USING BTREE (magic_text(oracle_text)) WITH (fillfactor = 100);

CREATE INDEX index_magic_cards_on_oracle_text_magic_text_pattern 
ON magic_cards 
USING BTREE (magic_text(oracle_text) text_pattern_ops) WITH (fillfactor = 100);

CREATE INDEX index_magic_cards_on_oracle_text_magic_gist_trgm 
ON magic_cards 
USING GIST (magic_text(oracle_text) gist_trgm_ops);

CREATE INDEX index_magic_cards_on_oracle_text_magic_gin_trgm 
ON magic_cards 
USING GIN (magic_text(oracle_text) gin_trgm_ops)
Run Code Online (Sandbox Code Playgroud)

这些索引以某种方式干扰了某些(但不是全部)类型的复杂正则表达式搜索。我无法确定特定的正则表达式符号或功能是否会导致问题。

这是一个示例(explain.depesz):

SELECT card_name 
FROM magic_cards 
WHERE magic_text(oracle_text) ~ '***:(?n)eldrazi\ (?!scion)';
Run Code Online (Sandbox Code Playgroud)

这不返回任何内容,并且根据查询规划器,它会在 上执行位图索引扫描index_magic_cards_on_oracle_text_magic_gin_trgm

这个扩展查询也扫描相同的索引,但没有找到任何东西 ( explain.depesz ):

SELECT card_name 
FROM magic_cards 
WHERE lower(coalesce(oracle_text, '')) ~ '***:(?n)eldrazi\ (?!scion)';
Run Code Online (Sandbox Code Playgroud)

但是,如果我强制 Postgres 不使用我的索引,这个查询就会有结果!( explain.depesz ) 下面有多行结果,对表进行顺序扫描。我在下面所做的只是将合并回退更改为?,这不应该影响结果:

SELECT card_name 
FROM magic_cards 
WHERE lower(coalesce(oracle_text, '?')) ~ '***:(?n)eldrazi\ (?!scion)';
Run Code Online (Sandbox Code Playgroud)

为什么使用索引会改变正则表达式搜索的结果?

(Postgres 9.6.1,pg_trgm 1.3)

jja*_*nes 5

对我来说,这看起来像是 pg_trgm 中的一个实时错误。我可以去掉大部分内容并仍然用这个简单的测试用例重现它:

create table foobar (x text);
insert into foobar values ('eldrazi scion'),('eldrazi scio');
create extension pg_trgm ;
create index  on foobar using gin (x gin_trgm_ops);
select * from foobar where x  ~ 'eldrazi (?!scion)';  -- returns 1 row
set enable_seqscan TO off;
select * from foobar where x  ~ 'eldrazi (?!scion)'; -- returns 0 rows
Run Code Online (Sandbox Code Playgroud)

请注意,最近修复了一个类似的错误(在尚未发布的代码中,提交 16500d2278ab3dd),但该修复并没有修复此错误。

我自己报告了这个错误,错误#14623

现在已经修复了。当 9.6.3 发布时,它应该包含错误修复。