patternsqlMinor
Query slow when using function in the WHERE clause
Viewed 0 times
thequerywherefunctionslowusingwhenclause
Problem
This is fast (49ms):
This is slow (15 seconds):
Function:
I am using PostgreSQL 12.
Why is the second variant slow?
v_cpf_numerico := ext.uf_converte_numerico(new.nr_cpf);
select cd_cliente into v_cd_cliente
from central.cliente where nr_cpf_cnpj = v_cpf_numerico;This is slow (15 seconds):
select cd_cliente into v_cd_cliente
from central.cliente where nr_cpf_cnpj = ext.uf_converte_numerico(new.nr_cpf);Function:
create or replace function ext.uf_converte_numerico(_input varchar(30)) returns bigint
as
$
begin
_input := regexp_replace(_input, '[^0-9]+', '', 'g');
if _input = '' then
return null;
end if;
return cast(_input as bigint);
end
$ language plpgsql;I am using PostgreSQL 12.
Why is the second variant slow?
Solution
Consider this simplified equivalent:
-
-
-
-
Aside: your input is
CREATE OR REPLACE FUNCTION ext.uf_converte_numerico(_input varchar(30))
RETURNS bigint LANGUAGE sql IMMUTABLE PARALLEL SAFE AS
$func$
SELECT NULLIF(regexp_replace(_input, '[^0-9]+', '', 'g'), '')::bigint;
$func$;-
IMMUTABLE, because it is, and for the reasons Laurenz explained.-
PARALLEL SAFE in Postgres 10 or later, because it is. Without the label, functions default to PARALLEL RESTRICTED, which disables parallel queries. This may or may not affect the query on display. But the 15 seconds you reported indicate you are operating on big tables. So it can make a huge difference in other queries.-
LANGUAGE SQL to enable function inlining, which won't matter much for the query on display (after you labelled it IMMUTABLE), but will simplify query plans and improve overall performance.-
NULLIF as minor simplification.Aside: your input is
varchar(30), which still allows out of range errors for bigint. Either consider varchar(18) to be sure. Or just make it text to remove the ineffective restriction.Code Snippets
CREATE OR REPLACE FUNCTION ext.uf_converte_numerico(_input varchar(30))
RETURNS bigint LANGUAGE sql IMMUTABLE PARALLEL SAFE AS
$func$
SELECT NULLIF(regexp_replace(_input, '[^0-9]+', '', 'g'), '')::bigint;
$func$;Context
StackExchange Database Administrators Q#251709, answer score: 5
Revisions (0)
No revisions yet.