Demo, all content is generated
Question

I added an index and the search is exactly as slow

Solved · 644 views · asked by ines_data · edited

Customer search in my CRM: select * from customers where name ilike '%' || $1 || '%' order by created_at desc limit 20. 400k rows, 1.8s. Cursor added create index on customers(name). Still 1.8s. explain says Seq Scan.

What I’ve tried

Tried a lower(name) index too. Ran analyze on the table.

Comment
Leading wildcard. A btree can't help with '%foo%'. marco_py · edited

3 answers

Marked as helpful by the asker
postgres_pete · edited

Marco's right. A btree index works for name ilike 'foo%' at best (and only with the right operator class), never for a wildcard at the start. For contains-search you want a trigram index:

create extension if not exists pg_trgm with schema extensions;
create index customers_name_trgm on customers using gin (name extensions.gin_trgm_ops);

That supports ilike '%foo%' directly. Search terms of 1-2 characters still scan a lot, so require 3+ characters in the UI.

Then drop the btree index Cursor added if nothing else uses it, unused indexes cost write speed.

Comment
1.8s -> 25ms. Dropped the other two indexes too. ines_data · edited
sarah_k_dev · edited

If you later want "john smit" to find "Smith, John", look at full-text search or a search column with both orders. Trigram is great for contains, less so for word order.

Comment
bytebarista · edited

If you can't find pg_trgm: Database > Extensions in the dashboard, search trgm, enable. Same as the SQL above.

Comment
yep found it there ines_data · edited