Thread: How to force Postgres to use index on ILIKE

How to force Postgres to use index on ILIKE

From
"Andrus"
Date:
I have UTF-8 Postgres 8.1 database on W2K3

Query

SELECT toode, nimetus
FROM toode
WHERE toode      ILIKE  'x10%' ESCAPE '!'
ORDER BY UPPER(toode     ),nimetus  LIMIT 100

runs 1 minute in first time for small table size.

Toode field type is CHAR(20)

How to create index on toode field so that query can use  it ?




Re: How to force Postgres to use index on ILIKE

From
Josh Berkus
Date:
Andrus,

> SELECT toode, nimetus
> FROM toode
> WHERE toode      ILIKE  'x10%' ESCAPE '!'
> ORDER BY UPPER(toode     ),nimetus  LIMIT 100
>
> runs 1 minute in first time for small table size.
>
> Toode field type is CHAR(20)

1) why are you using CHAR and not VARCHAR or TEXT?   CHAR will give you
problems using an index, period.

2) You can't use an index on ILIKE.  You can, however, use an index on
lower(field) if your query is properly phrased and if you've created an
expression index on lower(field).

--
--Josh

Josh Berkus
PostgreSQL @ Sun
San Francisco

Re: How to force Postgres to use index on ILIKE

From
"Andrus"
Date:
>> SELECT toode, nimetus
>> FROM toode
>> WHERE toode      ILIKE  'x10%' ESCAPE '!'
>> ORDER BY UPPER(toode     ),nimetus  LIMIT 100
>>
>> runs 1 minute in first time for small table size.
>>
>> Toode field type is CHAR(20)
>
> 1) why are you using CHAR and not VARCHAR or TEXT?   CHAR will give you
> problems using an index, period.

1. I haven't seen any example where VARCHAR is better that CHAR for indexing
2. I have a lot of existing code. Changing CHAR to VARCHAR requires probably
re-writing a lot of code, a huge work.

> 2) You can't use an index on ILIKE.

I'ts very sad. I expected that lower(toode) index can be used.


> You can, however, use an index on
> lower(field) if your query is properly phrased and if you've created an
> expression index on lower(field).

I tried by Postgres does not use index. Why ?

create index nimib2 on firma1.klient(lower(nimi) bpchar_pattern_ops);

explain analyze select nimi from firma1.klient where lower(nimi) like
'mokter%'

"Seq Scan on klient  (cost=0.00..9.79 rows=1 width=74) (actual
time=0.740..0.761 rows=1 loops=1)"
"  Filter: (lower((nimi)::text) ~~ 'mokter%'::text)"
"Total runtime: 0.877 ms"




Re: How to force Postgres to use index on ILIKE

From
Tom Lane
Date:
"Andrus" <eetasoft@online.ee> writes:
>> 1) why are you using CHAR and not VARCHAR or TEXT?   CHAR will give you
>> problems using an index, period.

> 1. I haven't seen any example where VARCHAR is better that CHAR for indexing

The advice you were given is good, even if the explanation is bad.
CHAR(n) is a poor choice for just about every purpose, because of all
the padding blanks it insists on storing and transmitting.  That adds
up to a lot of wasted space, I/O effort, and CPU cycles.

> I tried by Postgres does not use index. Why ?
> create index nimib2 on firma1.klient(lower(nimi) bpchar_pattern_ops);

Try to get over this fixation on CHAR.  That would work with
text_pattern_ops --- lower() returns TEXT, and TEXT is what the LIKE
operator accepts, so that's the opclass you need to use to optimize
lower() LIKE 'pattern'.

            regards, tom lane