Issue with creation of Partial_indexes (Immutable?)

Started by Ow Mun Hengover 17 years ago6 messagesgeneral
Jump to latest
#1Ow Mun Heng
Ow.Mun.Heng@wdc.com

CREATE INDEX idx_d_trh_code_id_partial
ON xmms.d_trh_table
USING btree
(code_id) where code_id not in ('P000','000') and code_id is not null;
ERROR: functions in index predicate must be marked IMMUTABLE

Just trying something new.

I want to create partial indexes on code_id which are not null and not
P000/000

the ones I want are like HMD11 or UE935 or OIOR11 etc.

not sure where the IMMUTABLE part is coming from..

Clue?

#2Ow Mun Heng
Ow.Mun.Heng@wdc.com
In reply to: Ow Mun Heng (#1)
Re: Issue with creation of Partial_indexes (Immutable?)

On Mon, 2008-08-25 at 12:23 +0800, Ow Mun Heng wrote:

CREATE INDEX idx_d_trh_code_id_partial
ON xmms.d_trh_table
USING btree
(code_id) where code_id not in ('P000','000') and code_id is not null;
ERROR: functions in index predicate must be marked IMMUTABLE

Just trying something new.

I want to create partial indexes on code_id which are not null and not
P000/000

the ones I want are like HMD11 or UE935 or OIOR11 etc.

not sure where the IMMUTABLE part is coming from..

BTW, this is on 8.2.9 Seems to work OK on 8.3.3.

However, got a question on usage of this index.

I've got 2 indexes.

case #1

CREATE INDEX idx_d_trh_code_id
ON xmms.d_trh_table
USING btree
(code_id)

case#2


CREATE INDEX idx_d_trh_code_id_partial
ON xmms.d_trh_table
USING btree
(code_id)where code_id not in ('P000','000') and code_id is not null;

when I do a

select * from d_trh_table where code_id = 'UAH11'

it will still use the full index which is idx_d_trh_code_id instead of the partial index.

it is only when I do a

select * from d_trh_table where code_id = 'UAH11' and code_id not in
('P000','000') will it use the partial index.

I would _think_ that this is expected based on the documentation I'm
reading. Is it?
(need confirmation)

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Ow Mun Heng (#2)
Re: Issue with creation of Partial_indexes (Immutable?)

Ow Mun Heng <Ow.Mun.Heng@wdc.com> writes:

On Mon, 2008-08-25 at 12:23 +0800, Ow Mun Heng wrote:

CREATE INDEX idx_d_trh_code_id_partial
ON xmms.d_trh_table
USING btree
(code_id) where code_id not in ('P000','000') and code_id is not null;
ERROR: functions in index predicate must be marked IMMUTABLE

BTW, this is on 8.2.9 Seems to work OK on 8.3.3.

I suppose code_id is varchar or some such?

Try "where code_id::text not in ...". There's an array type coercion
underlying the right-hand side of the NOT IN, and 8.2 had some problems
with correctly identifying the volatility of such coercions.

regards, tom lane

#4Ow Mun Heng
Ow.Mun.Heng@wdc.com
In reply to: Tom Lane (#3)
Partial Indexes Not being Used [WAS]Re: Partial_indexes (Immutable?)

On Mon, 2008-08-25 at 10:18 -0400, Tom Lane wrote:

Ow Mun Heng <Ow.Mun.Heng@wdc.com> writes:

On Mon, 2008-08-25 at 12:23 +0800, Ow Mun Heng wrote:

CREATE INDEX idx_d_trh_code_id_partial
ON xmms.d_trh_table
USING btree
(code_id) where code_id not in ('P000','000') and code_id is not null;
ERROR: functions in index predicate must be marked IMMUTABLE

BTW, this is on 8.2.9 Seems to work OK on 8.3.3.

I suppose code_id is varchar or some such?

Yep

Try "where code_id::text not in ...". There's an array type coercion
underlying the right-hand side of the NOT IN, and 8.2 had some problems
with correctly identifying the volatility of such coercions.

This now works.

Prior to that, I was trying
WHERE code_id::text <> 'P000'::text OR code_id::text <> '000'::text
Which is basically a variant of the above (only that I didn't realise
it!)

After a few more investigation on the usefulness of the partial indexes,
I found that, it really isn't all that useful, perhaps some experts can
shed some light.

explain analyse select * from d_trh_pbert where code_id IN( 'HAMA2');
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
Index Scan using idx_d_trh_pbert_eval on d_trh_pbert (cost=0.00..26669.96 rows=7125 width=216) (actual time=0.066..2.491 rows=1840 loops=1)
Index Cond: ((code_id)::text = 'HAMA2'::text)
Total runtime: 4.018 ms

explain analyse select * from d_trh_pbert where code_id IN( 'HAMA2','HAMA3');
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on d_trh_pbert (cost=262.02..53641.68 rows=14249 width=216) (actual time=0.926..4.858 rows=3556 loops=1)
Recheck Cond: ((code_id)::text = ANY (('{HAMA2,HAMA3}'::character varying[])::text[]))
-> Bitmap Index Scan on idx_d_trh_pbert_eval (cost=0.00..258.45 rows=14249 width=0) (actual time=0.853..0.853 rows=3556 loops=1)
Index Cond: ((code_id)::text = ANY (('{HAMA2,HAMA3}'::character varying[])::text[]))
Total runtime: 7.809 ms

It doesn't even hit the partial indexes.

explain analyse select * from d_trh_pbert where code_id IN( 'HAMA2','HAMA3') and code_id not in ('P000','000') and code_id is not null;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on d_trh_pbert (cost=259.90..53675.18 rows=5788 width=216) (actual time=0.916..7.477 rows=3556 loops=1)
Recheck Cond: ((code_id)::text = ANY (('{HAMA2,HAMA3}'::character varying[])::text[]))
Filter: ((code_id IS NOT NULL) AND ((code_id)::text <> ALL (('{P000,000}'::character varying[])::text[])))
-> Bitmap Index Scan on idx_d_trh_pbert_eval (cost=0.00..258.45 rows=14249 width=0) (actual time=0.835..0.835 rows=3556 loops=1)
Index Cond: ((code_id)::text = ANY (('{HAMA2,HAMA3}'::character varying[])::text[]))
Total runtime: 10.510 ms

hmxmms=# explain analyse select * from d_trh_pbert where code_id IN( 'HAMA3') and code_id not in ('P000','000') and code_id is not null;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
Index Scan using idx_d_trh_pbert_eval on d_trh_pbert (cost=0.00..26687.77 rows=2894 width=216) (actual time=0.077..3.506 rows=1716 loops=1)
Index Cond: ((code_id)::text = 'HAMA3'::text)
Filter: ((code_id)::text <> ALL (('{P000,000}'::character varying[])::text[]))
Total runtime: 5.025 ms

The 2 indexes.

CREATE INDEX idx_d_trh_pbert_eval_partial2
ON xmms.d_trh_pbert
USING btree
(code_id)
WHERE (code_id::text <> ALL (ARRAY['P000'::text, '000'::text])) AND code_id IS NOT NULL; (size ~500MB)

CREATE INDEX idx_d_trh_pbert_eval
ON xmms.d_trh_pbert
USING btree
(code_id); (size ~1.5G)

This table has approx 73 million rows and is 35 columns wide.
Stats on the code_id column is at 200 and there's ~1k of distinct values in it.

code_id is varchar(5)

I was hoping that doing the partial index will make things faster as ~70-80% of the time, it's ('P000','000')

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Ow Mun Heng (#4)
Re: Partial Indexes Not being Used [WAS]Re: Partial_indexes (Immutable?)

Ow Mun Heng <Ow.Mun.Heng@wdc.com> writes:

On Mon, 2008-08-25 at 10:18 -0400, Tom Lane wrote:

I suppose code_id is varchar or some such?

Yep
After a few more investigation on the usefulness of the partial indexes,
I found that, it really isn't all that useful, perhaps some experts can
shed some light.

I poked at that example a bit more earlier today, and found that 8.3
has a problem that's interfering with optimizing x IN ('y','z') type
clauses when x is varchar. If you don't mind building a local copy,
see if this patch helps you any:
http://archives.postgresql.org/pgsql-committers/2008-08/msg00254.php

regards, tom lane

#6Ow Mun Heng
Ow.Mun.Heng@wdc.com
In reply to: Tom Lane (#5)
Re: Partial Indexes Not being Used [WAS]Re: Partial_indexes (Immutable?)

On Tue, 2008-08-26 at 00:58 -0400, Tom Lane wrote:

Ow Mun Heng <Ow.Mun.Heng@wdc.com> writes:

On Mon, 2008-08-25 at 10:18 -0400, Tom Lane wrote:

I suppose code_id is varchar or some such?

Yep
After a few more investigation on the usefulness of the partial indexes,
I found that, it really isn't all that useful, perhaps some experts can
shed some light.

I poked at that example a bit more earlier today, and found that 8.3
has a problem that's interfering with optimizing x IN ('y','z') type
clauses when x is varchar. If you don't mind building a local copy,
see if this patch helps you any:
http://archives.postgresql.org/pgsql-committers/2008-08/msg00254.php

I wouldn't mind if I have a box with a compiler installed or if i have a
NON-Production Box at all.

:-(