Thread: Expression indexes and casts

Expression indexes and casts

From
Stephan Szabo
Date:
    I'm playing with a type that has no equality operator, but
does provide an implicit cast to text.  While working with this, I found
that the in some cases an expression index on the cast value doesn't
seem to be considered.

sszabo=# create index foo1i on foo1((a::text));
CREATE INDEX

sszabo=# set enable_seqscan=off;
SET

sszabo=# explain select * from foo1 where a='bbb';
                             QUERY PLAN
---------------------------------------------------------------------
 Seq Scan on foo1  (cost=100000000.00..100000001.05 rows=1 width=32)
   Filter: ((a)::text = 'bbb'::text)
(2 rows)

sszabo=# explain select * from foo1 where a::text='bbb'::text;
                            QUERY PLAN
-------------------------------------------------------------------
 Index Scan using foo1i on foo1  (cost=0.00..4.68 rows=1 width=32)
   Index Cond: ((a)::text = 'bbb'::text)

I haven't done any looking around yet (about to head off to work), but it
looks like in the case where the system decides to cast a to text in order
to get a working equality, the index isn't used, whereas in the case where
I explicitly cast it, it can.

Re: Expression indexes and casts

From
Tom Lane
Date:
Stephan Szabo <sszabo@megazone.bigpanda.com> writes:
> I haven't done any looking around yet (about to head off to work), but it
> looks like in the case where the system decides to cast a to text in order
> to get a working equality, the index isn't used, whereas in the case where
> I explicitly cast it, it can.

I think the problem is that explicit and implicit casts are marked
differently in the cast parse node, causing equal() to consider the two
expressions different.

There is currently a hack involving a "don't care" setting for this
field, but it doesn't help you.  I wonder if it would be better to make
equal() explicitly ignore the cast-type field.  It seems like that could
break other things though :-(.

A narrower patch would be to change the cast type field to don't-care in
the copy of the parse tree that is made for planner user.

[ thinks some more... ]  On the other hand, there are cases where
explicit and implicit casting are actually semantically different (think
varchar() and char() length constraints).  Maybe the don't-care business
is itself a bug, and you're just stuck.

            regards, tom lane

Re: Expression indexes and casts

From
Stephan Szabo
Date:
On Tue, 9 Mar 2004, Tom Lane wrote:

> Stephan Szabo <sszabo@megazone.bigpanda.com> writes:
> > I haven't done any looking around yet (about to head off to work), but it
> > looks like in the case where the system decides to cast a to text in order
> > to get a working equality, the index isn't used, whereas in the case where
> > I explicitly cast it, it can.
>
> I think the problem is that explicit and implicit casts are marked
> differently in the cast parse node, causing equal() to consider the two
> expressions different.
>
> There is currently a hack involving a "don't care" setting for this
> field, but it doesn't help you.  I wonder if it would be better to make
> equal() explicitly ignore the cast-type field.  It seems like that could
> break other things though :-(.
>
> A narrower patch would be to change the cast type field to don't-care in
> the copy of the parse tree that is made for planner user.
>
> [ thinks some more... ]  On the other hand, there are cases where
> explicit and implicit casting are actually semantically different (think
> varchar() and char() length constraints).  Maybe the don't-care business
> is itself a bug, and you're just stuck.

Is it possible to make an index on the implicitly cast version (or what
would that take - I'm not sure how to syntactically note that in any
case)?  I don't really care about the explicit cast case actually.


Re: Expression indexes and casts

From
Tom Lane
Date:
Stephan Szabo <sszabo@megazone.bigpanda.com> writes:
> On Tue, 9 Mar 2004, Tom Lane wrote:
>> I think the problem is that explicit and implicit casts are marked
>> differently in the cast parse node, causing equal() to consider the two
>> expressions different.
>>
>> A narrower patch would be to change the cast type field to don't-care in
>> the copy of the parse tree that is made for planner uses.

I have applied a patch to CVS tip that does this.  It's fairly small and
would be safe to back-patch into 7.4 if you are feeling in need of a
near-term solution.  So for example:

regression=# create table foo (f1 int);
CREATE TABLE
regression=# create index fooi on foo ((f1::numeric));
CREATE INDEX
regression=# explain select * from foo where f1 = 44.44;
                           QUERY PLAN
-----------------------------------------------------------------
 Index Scan using fooi on foo  (cost=0.00..17.07 rows=5 width=4)
   Index Cond: ((f1)::numeric = 44.44)
(2 rows)

whereas 7.4 would fail to recognize that the index is applicable.

>> [ thinks some more... ]  On the other hand, there are cases where
>> explicit and implicit casting are actually semantically different (think
>> varchar() and char() length constraints).  Maybe the don't-care business
>> is itself a bug, and you're just stuck.

This concern was a red herring --- any semantic impact of the coercion
type is reflected in the parameters of the associated function call.
The CoercionForm itself doesn't affect much of anything except
reverse-listing in ruleutils.c.

> Is it possible to make an index on the implicitly cast version (or what
> would that take - I'm not sure how to syntactically note that in any
> case)?

I can't see a good way to do that either :-(

            regards, tom lane