Re: Query performance strangeness..

From: Richard Huxton <dev(at)archonet(dot)com>
To: Steve Spicklemire <steve(at)spvi(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: Query performance strangeness..
Date: 2007-07-19 11:06:42
Message-ID: 469F45C2.4010700@archonet.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

Steve Spicklemire wrote:
>
> Here is the function body... the data is stored in and XML "pickle". I
> had hoped that it would only be called in building the index.
>
> Since the query uses it in the 'filter' step.. I'm not sure if it's
> using the index or not.
>
> Does marking the function immutable help the planner know whether it can
> use the index or not?

Well, since you've got an index using it, you *must* have already marked
it immutable. Presumably it's not genuinely immutable though.

> CCOC=# \df+ get_cem_for_directBurial
> List of functions
> Schema | Name | Result data type | Argument data
> types | Owner | Language | Source code | Description
> --------+--------------------------+------------------+---------------------+---------+----------+-------------+-------------
>
> public | get_cem_for_directburial | text | character
> varying | webuser | plpgsql |
> DECLARE
> personID ALIAS for $1;
> qResult RECORD;
>
> BEGIN
> SELECT INTO qResult
> get_xml_value('/params/param/value/struct/member/*[contains(text(),''cemid'')]/parent::*/value/string/text()','People',personID,'')
> as cem;
> return qResult.cem;
> END;

That might be stable, but I don't see how it could be immutable unless
the xml is in your "people" table.

> CCOC=# \d people
> Table "public.people"
> Column | Type
> | Modifiers
> ------------+-----------------------------+------------------------------------------------------------------------------------
>
> personid | character varying(40) | not null default
> ('AUTO'::text || (nextval(('People_seq'::text)::regclass))::text)
> modified | timestamp without time zone | default now()
> created | timestamp without time zone | default now()
> enabled | boolean |
> first | character varying(40) |
> middle | character varying(15) |
> last | character varying(80) |
> gender | character varying(2) |
> sbirthdate | character varying(30) |
> sdeathdate | character varying(30) |
> status | character varying(30) |
> Indexes:
> "people_pkey" PRIMARY KEY, btree (personid)
> "idx_people_cemid" btree (get_cem_for_directburial(personid))
> "idx_people_lower_concat3_last" btree (lower_concat3("last",
> "first", (middle::text || personid::text)::character varying))
> "idx_people_servicenum" btree
> (get_numeric_servicenumber_for_personid(personid))
> "idx_people_status" btree (status)
> "idx_people_take4_personid_" btree (take4(personid))

>>> Filter: (('STJ'::text =
>>> get_cem_for_directburial(personid)) AND ((status)::text <> 'R'::text)
>>> AND ((status)::text <> 'F'::text))

>>> Filter: (('HCC'::text =
>>> get_cem_for_directburial(personid)) AND ((status)::text <> 'R'::text)
>>> AND ((status)::text <> 'F'::text))

> If the query is actually calling get_cem_for_directburial during the
> query... then I'm sunk. I'll have to move that data to a regular indexed
> field. I can do that... it's just a lot of work. ;-(

Where you see it calling "Filter" it's evaluating the function I'm
afraid. It's possible for the executor to call the function more than
once too.

You've got so much data hidden behind functions, it's unlikely you'll
get the planner to make any informed decisions as to the quickest plan.

You're testing for inequality on status, so unless <> F / R is uncommon
a partial query on that probably won't help much either.

Just to be sure, cheat. Run get_cem_for_directburial() over the whole
people table and dump the results into a cache table. Then, try the same
query with a function that just does a table lookup - see if that makes
things faster.

Then I'd just write a couple of trigger functions to keep the cache
table up-to-date and join against it. That will let the planner see
common values and make better predictions for its plans.

If you (or anyone else) would like to explore functional indexes and
calling, I've attached a small demo script.

--
Richard Huxton
Archonet Ltd

Attachment Content-Type Size
func_index.sql text/x-sql 592 bytes

In response to

Browse pgsql-general by date

  From Date Subject
Next Message Paul Codler 2007-07-19 12:52:30 IN clause performance
Previous Message Steve Spicklemire 2007-07-19 10:23:21 Re: Query performance strangeness..