Horrible/never returning performance using stable function on WHERE clause

From: Achilleas Mantzios <achill(at)matrix(dot)gatewaynet(dot)com>
To: pgsql-general General <pgsql-general(at)postgresql(dot)org>
Subject: Horrible/never returning performance using stable function on WHERE clause
Date: 2016-03-29 07:01:38
Message-ID: 56FA2852.3070600@matrix.gatewaynet.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

Hello list,
I have written some functions to extract some data from our DB, from an hierarchical structure, the problem is that if a function doing lookups is defined as STABLE in the WHERE clause the performance
is horrible. What I am trying to achieve is given a specific node in an hierarchical structure (a machine definition) to find all its equivalent sister nodes and then for a specific instance of this
hierarchy to find the max RH (running hours) among all sister nodes.I am using some functions/opers from intarray. Here are the functions :

Compares two nodes for sister property:

CREATE OR REPLACE FUNCTION public.is_defid_sister_node(vdefid1 integer, vdefid2 integer)
RETURNS boolean
LANGUAGE plpgsql
STABLE
AS $function$DECLARE
vparents1 INTEGER[];
vparents2 INTEGER[];
descr1 TEXT;
descr2 TEXT;
i INTEGER;
BEGIN

SELECT COALESCE(partid,0)||'__'||regexp_replace(coalesce(description,''),'[nN][oO]([0-9]+)',''),parents into descr1,vparents1 FROM machdefs where defid=vdefid1;
SELECT COALESCE(partid,0)||'__'||regexp_replace(coalesce(description,''),'[nN][oO]([0-9]+)',''),parents into descr2,vparents2 FROM machdefs where defid=vdefid2;

IF (level(vparents1) = 0 AND level(vparents2) = 0) THEN
RETURN vdefid1=vdefid2;
ELSIF (level(vparents1) <> level(vparents2)) THEN
RETURN false;
ELSE
RETURN ((descr1=descr2) AND is_defid_sister_node(first(vparents1),first(vparents2)));
END IF;

END;$function$

Finds the set of sister nodes for a given node:

CREATE OR REPLACE FUNCTION public.get_machdef_sister_defids(vdefid integer)
RETURNS INTEGER[]
LANGUAGE plpgsql
STABLE
AS $function$
DECLARE
tmp INTEGER[];
BEGIN

select (select array_agg(mdsis.defid) FROM machdefs mdsis WHERE mdsis.machtypeid=md.machtypeid AND level(mdsis.parents)=level(md.parents) AND last(mdsis.parents)=last(md.parents) AND
is_defid_sister_node(mdsis.defid,md.defid) ) INTO tmp from machdefs md where md.defid=vdefid;

IF (tmp IS NULL) THEN
tmp := '{}';
END IF;
RETURN tmp;

END;
$function$

Finds max RH for a given tree instance among all sister nodes of a given node :

CREATE OR REPLACE FUNCTION public.get_machdef_sister_defids_maxrh(vvslid INTEGER,vdefid INTEGER)
RETURNS INTEGER
LANGUAGE plpgsql
STABLE
AS $function$
DECLARE
tmp INTEGER;
BEGIN
select max(rh) into tmp from items where vslwhid=vvslid and itoar(defid) ~ get_machdef_sister_defids(vdefid);
RETURN tmp;
END;
$function$

Query :
select get_machdef_sister_defids_maxrh(479,319435);

never ends (I have waited till 2-3 minutes), however, *doing the wrong thing* and declaring get_machdef_sister_defids as IMMUTABLE makes the above call return fast :

# select get_machdef_sister_defids_maxrh(479,319435);
get_machdef_sister_defids_maxrh
---------------------------------
10320
(1 row)

Time: 110.211 ms

We are using PostgreSQL 9.3. Shouldn't the optimizer use a single call to
get_machdef_sister_defids in get_machdef_sister_defids_maxrh ??

Defining get_machdef_sister_defids back to STABLE and forcing get_machdef_sister_defids_maxrh to only call get_machdef_sister_defids once makes things work again :

CREATE OR REPLACE FUNCTION public.get_machdef_sister_defids_maxrh(vvslid integer, vdefid integer)
RETURNS integer
LANGUAGE plpgsql
STABLE
AS $function$
DECLARE
tmp INTEGER;
tmppars INTEGER[];
BEGIN
tmppars := get_machdef_sister_defids(vdefid);
select max(rh) into tmp from items where vslwhid=vvslid and itoar(defid) ~ tmppars;
RETURN tmp;
END;
$function$

# select get_machdef_sister_defids_maxrh(479,319435);
get_machdef_sister_defids_maxrh
---------------------------------
10320
(1 row)

Time: 111.318 ms

Is this expected ?

--
Achilleas Mantzios
IT DEV Lead
IT DEPT
Dynacom Tankers Mgmt

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Lifepillar 2016-03-29 08:14:58 [ANN] pgsql v1.0: PostgreSQL ftplugin for Vim
Previous Message Jerry Sievers 2016-03-28 23:31:26 Re: How to quote the COALESCE function?