postgresql - 让 LIKE 搜索使用 citext 表达式上的索引

标签 postgresql indexing expression

背景: -- 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/

相关文章:

javascript - 在 PostgreSQL 中 COPY/INSERT ON CASCADE 的最佳方法是什么?

django - Sentry 升级错误

javascript - RegExp,如何在 javascript 中连接字符串来创建动态正则表达式?

.htaccess - 带有 HTACCESS 文件的干净且 SEO 友好的 URL

python - Pandas 从日期时间索引中删除秒数

c# - 如何重构linq表达式树

postgresql - 配置安全组以通过客户端 psycopg2 连接到 postgres RDS

sql 生成唯一的表/ View 名称

list - 如何更改 F# 中特定索引处列表中的项目? (属性 'Item'无法设置)

python - 磁盘读取会减慢 MySQL 中的 INSERT 速度