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)
对我来说,这看起来像是 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 发布时,它应该包含错误修复。