背景: -- RDS 上的 Postgres 11.4,macOS 上的 11.5。 -- 在我的测试设置中,record_changes_log_detail 表大约有 8M。 -- old_value 字段的类型为 citext。 -- 该字段中的值长度范围从 1 个字符到超过 5,000 个字符。大多数都很短。
据我了解,我需要在此处使用表达式索引,因为我的某些值对于 B 树条目来说太长。根据 Postgres 11 发行说明:
“允许创建可供 citext 列上的 LIKE 比较使用的索引 (Alexey Chernyshov) 为此,必须使用 citext_pattern_ops 运算符类创建索引。”
https://www.postgresql.org/docs/11/release-11.html
这是我的示例数据的索引定义:
CREATE INDEX record_changes_log_detail_old_value_ix_btree
ON record_changes_log_detail
USING btree ((substring(old_value,1,1024)::citext) citext_pattern_ops);
如果我运行此查询分析,我可以看到使用了索引:
set max_parallel_workers_per_gather = 0; -- Don't tempt the planner to run a sequential scan.
explain analyze
select * from record_changes_log_detail where substring(old_value,1,1024)::citext = 'Gold Kerrison Neuro';
因此,= 搜索按预期工作。但是,此查询不使用索引:
select * from record_changes_log_detail where substring(old_value,1,1024)::citext LIKE 'Gold Kerrison Neuro%';
是否有一些技巧可以让 citext 索引与我错过的 LIKE 查询一起使用,或者这更有可能是一个错误?作为比较,如果您使用 text_pattern_ops 构建 LIKE 查询确实会使用索引。当然,它是区分大小写的。
区分大小写
这里是关于区分大小写的评论的后续内容。我认为“pg_trgm”不区分大小写,但没有时间进行彻底审查。作为快速检查,这三个比较均返回 1,即完美匹配。
select similarity('hello world','hello world');
select similarity('hello world','HELLO WORLD');
select similarity('Hello World','hello world');
最佳答案
我向 PG bugs 邮件列表发送了一条有关此主题的消息,并从 Tom Lane 得到了答复。我对答案的总结是“这是一个文档错误”。 citext_pattern_ops 不支持 LIKE 查询。
我想为了文件的缘故我应该在这里发布信息。
并且,根据 Laurenz Albe 的建议,我尝试了 Postgres tri-gram 实现。他们统治!
DROP INDEX IF EXISTS record_changes_log_detail_old_value_ix_tgrm;
CREATE INDEX record_changes_log_detail_old_value_ix_tgrm
ON record_changes_log_detail
USING gin (old_value gin_trgm_ops);
当您使用 citext 时,秘诀是将您的值转换为::text,如下所示:
select * from record_changes_log_detail
where old_value::text LIKE '%Gold Kerrison Neuro%';
通过解释分析运行该命令以确认索引已被使用。
关于postgresql - 让 LIKE 搜索使用 citext 表达式上的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58002609/