Thread: BUG #5797: Strange bug with hstore

BUG #5797: Strange bug with hstore

From
"Maxim Boguk"
Date:
The following bug has been logged online:

Bug reference:      5797
Logged by:          Maxim Boguk
Email address:      Maxim.Boguk@gmail.com
PostgreSQL version: 8.4.4
Operating system:   Freebsd
Description:        Strange bug with hstore
Details:

One day ago I analyzed slow query for one of my clients and found strange
query plan. After some digging I localized something which I think is bug.

The bug can be seen in these two explains:

Good explain:
billing=# EXPLAIN SELECT * from domains where
name='"name"=>"somedomain"'::hstore->'name';
                                  QUERY PLAN
----------------------------------------------------------------------------
--
 Index Scan using domains_name on domains  (cost=0.00..0.29 rows=1
width=230)
   Index Cond: ((name)::text = 'somedomain'::text)
(index used)

Bad explain:
billing=# EXPLAIN SELECT * from domains where
name='"name"=>"somedomain"'::text::hstore->'name';
                                             QUERY PLAN
----------------------------------------------------------------------------
------------------------
 Seq Scan on domains  (cost=0.00..7775.91 rows=1 width=230)
   Filter: ((name)::text = (('"name"=>"somedomain"'::text)::hstore ->
'name'::text))
(index not used)

As can be seen no index was used in second case. I tested some variants and
found conditions like field1=other_field::text::hstore->'key' never using
index on field1.

Ofcourse client case was much more complicated and contained 9 joins... but
troublesome part was looked like:

billing=# EXPLAIN SELECT
es.params
FROM services es
JOIN domains dm ON dm.name = (es.params::hstore)->'name'
WHERE
es.shortname = 'exchange_accepted_domain'
;
                                           QUERY PLAN
----------------------------------------------------------------------------
---------------------
 Nested Loop  (cost=0.00..27990293.56 rows=3289 width=32)
   Join Filter: ((dm.name)::text = ((es.params)::hstore -> 'name'::text))
   ->  Index Scan using services_shortname on services es  (cost=0.00..68.50
rows=2406 width=32)
         Index Cond: ((shortname)::text = 'exchange_accepted_domain'::text)
   ->  Seq Scan on domains dm  (cost=0.00..3918.31 rows=385760 width=15)
(5 rows)

Re: BUG #5797: Strange bug with hstore

From
Tom Lane
Date:
"Maxim Boguk" <Maxim.Boguk@gmail.com> writes:
> Bad explain:
> billing=# EXPLAIN SELECT * from domains where
> name='"name"=>"somedomain"'::text::hstore->'name';
>                                              QUERY PLAN
> ----------------------------------------------------------------------------
> ------------------------
>  Seq Scan on domains  (cost=0.00..7775.91 rows=1 width=230)
>    Filter: ((name)::text = (('"name"=>"somedomain"'::text)::hstore ->
> 'name'::text))
> (index not used)

The reason for this is that hstore fails to label its I/O functions as
immutable (or even stable) in 8.4.  This is fixed in 9.0.

            regards, tom lane

Re: BUG #5797: Strange bug with hstore

From
Maxim Boguk
Date:
On Tue, Dec 21, 2010 at 7:48 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> "Maxim Boguk" <Maxim.Boguk@gmail.com> writes:
>> Bad explain:
>> billing=3D# EXPLAIN SELECT * from domains where
>> name=3D'"name"=3D>"somedomain"'::text::hstore->'name';
>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0QUERY PLAN
>> ------------------------------------------------------------------------=
----
>> ------------------------
>> =C2=A0Seq Scan on domains =C2=A0(cost=3D0.00..7775.91 rows=3D1 width=3D2=
30)
>> =C2=A0 =C2=A0Filter: ((name)::text =3D (('"name"=3D>"somedomain"'::text)=
::hstore ->
>> 'name'::text))
>> (index not used)
>
> The reason for this is that hstore fails to label its I/O functions as
> immutable (or even stable) in 8.4. =C2=A0This is fixed in 9.0.
>
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0regards, tom lane
>

Sorry for late responce and thank you for clarification.

My research of that problem leads me to conclusion that can be fixed
on 8.4.4 with:
 ALTER FUNCTION hstore_in(cstring) IMMUTABLE;
but is it really safe?
Or text->hstore conversion in 8.4 is really VOLATILE as labeled in
hstrore module?

Regards, Maxim

Re: BUG #5797: Strange bug with hstore

From
Robert Haas
Date:
On Sun, Dec 26, 2010 at 12:29 AM, Maxim Boguk <maxim.boguk@gmail.com> wrote:
> On Tue, Dec 21, 2010 at 7:48 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> "Maxim Boguk" <Maxim.Boguk@gmail.com> writes:
>>> Bad explain:
>>> billing=3D# EXPLAIN SELECT * from domains where
>>> name=3D'"name"=3D>"somedomain"'::text::hstore->'name';
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0QUERY PLAN
>>> -----------------------------------------------------------------------=
-----
>>> ------------------------
>>> =A0Seq Scan on domains =A0(cost=3D0.00..7775.91 rows=3D1 width=3D230)
>>> =A0 =A0Filter: ((name)::text =3D (('"name"=3D>"somedomain"'::text)::hst=
ore ->
>>> 'name'::text))
>>> (index not used)
>>
>> The reason for this is that hstore fails to label its I/O functions as
>> immutable (or even stable) in 8.4. =A0This is fixed in 9.0.
>>
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0regards, tom lane
>>
>
> Sorry for late responce and thank you for clarification.
>
> My research of that problem leads me to conclusion that can be fixed
> on 8.4.4 with:
> =A0ALTER FUNCTION hstore_in(cstring) IMMUTABLE;
> but is it really safe?
> Or text->hstore conversion in 8.4 is really VOLATILE as labeled in
> hstrore module?

I think your proposed change is safe.

--=20
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company