Lower() vs ilike on postgresql

Posted on

Question :

What I want to do is to check if value of column equals some string, but case insensitive. Is there a performance difference when using ilike without wildcards (percents) and lower() ?

I was planning to create index on lower(column_name) and use lower(column_name) = value (value is lower case already) but it turns out that ORM I’m using doesn’t allow me to use lower() in a pretty way (but has convenient method for ilike). Will column_name ilike 'value' use lower(column_name) index?

Answer :

Measure it and see, using explain analyze on test data.

I would expect a significant difference between an expression index on lower(col) with lower(col) = lower('constant') vs use of col ilike 'constant', with the expression index on lower(col) the faster.

That’s because Pg can do a bitmap index scan with the expression index, but for the ilike it’ll have to do a seqscan. AFAIK a text_pattern_ops index (useful for LIKE) won’t do you any good for ILIKE.

The other question is whether the difference is worth caring about, and that depends on your data and workload. Sometimes it’s smarter to just choose the slower but easier option and spend yourtime/effort elsewhere.

Will column_name ilike ‘value’ use lower(column_name) index?

No. Nor will it use an index on lower(column_name) text_pattern_ops. AFAIK there is no way to index a case-insensitive pattern match (ILIKE or ~~*) on a case-sensitive text/varchar in PostgreSQL at this time.

I don’t think the citext type changes this, though it does make things more convenient.

If you build an index like:

CREATE INDEX idx_indexname
ON yourtable (LOWER(columnname) ASC NULLS LAST);

Lower will use index.

ILIKE will use index, but only in some case. I suggest starting here:

Leave a Reply

Your email address will not be published. Required fields are marked *