Background: -- Postgres 11.4 on RDS, 11.5 on macOS at home. -- The record_changes_log_detail table has about 8M in my test setup. -- The old_value field is of type citext. -- Values in the field range in length from 1 character to over 5,000. Most are short.
As far as I understand it, I need to use an expression index here as some of my values are too long for a B-tree entry. According to the Postgres 11 release notes:
"Allow creation of indexes that can be used by LIKE comparisons on citext columns (Alexey Chernyshov) To do this, the index must be created using the citext_pattern_ops operator class."
https://www.postgresql.org/docs/11/release-11.html
Here is such an index definition for my sample data:
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);
If I run this query analysis, I can see that the index is used:
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';
So, the = search works as hoped for. However, this query does not use the index:
select * from record_changes_log_detail where substring(old_value,1,1024)::citext LIKE 'Gold Kerrison Neuro%';
Is there some trick to getting citext indexes to work with LIKE queries that I've missed, or is this more likely a bug? For comparison, a LIKE query does use the index if you build it with text_pattern_ops. But then, of course, it's case-sensitive.
Case-sensitivity
Follow-up here to a comment on case-sensitivity. I think that `pg_trgm' is case-blind, but don't have time for a thorough review. As a quick check, these three comparisons each return 1, a perfect match.
select similarity('hello world','hello world');
select similarity('hello world','HELLO WORLD');
select similarity('Hello World','hello world');