I have a query where I need to call a SQL function to format a particular column in the query. The formatting needed is very similar to formatting a phone number, ie. changing 1234567890 into (123)456-7890.
I’ve read that calling a function from a select statement could be a performance killer, and it was kind of reflected in my situation, the time the query took more than tripled and I did not think the function would take this much longer. The function runs in linear time but does use SQL loops. To give an idea of the size of the database this particular query returns about 220,000 rows. The run time of the query went from < 3s to > 9s when running without calling the function vs. running calling the function. The column that needs formatting isn’t indexed or used in a join condition or where clause.
Is the performance drop here expected or is there something I can do to improve it?
This is the function in question:
CREATE OR REPLACE FUNCTION fn(bigint)
RETURNS character varying LANGUAGE plpgsql AS
$BODY$
DECLARE
v_chars varchar[];
v_ret varchar;
v_length int4;
v_count int4;
BEGIN
if ($1 isnull or $1 = 0) then
return null;
end if;
v_chars := regexp_split_to_array($1::varchar,'');
v_ret := '';
v_length := array_upper (v_chars,1);
v_count := 0;
for v_index in 1..11 loop
v_count := v_count + 1;
if (v_index <= v_length) then
v_ret := v_chars[v_length - (v_index - 1)] || v_ret;
else
v_ret := '0' || v_ret;
end if;
if (v_count <= 6 and (v_count % 2) = 0) then
v_ret := '.' || v_ret;
end if;
end loop;
return v_ret;
END
$BODY$
It depends on the specifics of the function. To find out how much a bare function call will cost, create dummy functions like:
And try your query again.
If then you wonder why your function is slow, add it to your question.
Solution for updated question
Your function could be improved in many places, but there is a more radical solution:
Many times faster, obviously. More about
to_char()in the manual.Consider the following demo:
to_char()is only prepared for up to 11 decimal digits, as you can see.Can easily be extended, if need should be.