これは高速です(49ミリ秒):
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;
これは遅い(15秒):
select cd_cliente into v_cd_cliente
from central.cliente where nr_cpf_cnpj = ext.uf_converte_numerico(new.nr_cpf);
関数:
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;
PostgreSQL 12を使用しています。
2番目のバリアントが遅いのはなぜですか?
この単純化された同等のものを検討してください:
_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
、それはがであり、理由により ローレンツは説明した だからです。
_PARALLEL SAFE
_ Postgres 10以降では、isであるためです。ラベルがない場合、関数はデフォルトで_PARALLEL RESTRICTED
_になり、並列クエリが無効になります。これは、表示中のクエリに影響する場合と影響しない場合があります。しかし、報告した15秒は、大きなテーブルを操作していることを示しています。そのため、他のクエリでhugeの違いが生じる可能性があります。
_LANGUAGE SQL
_ 有効にするには 関数のインライン化 、これは表示されているクエリではそれほど重要ではありませんが(IMMUTABLE
とラベル付けした後)、クエリプランを簡素化し、全体的なパフォーマンスを向上させます。
NULLIF
単純化してください。
余談ですが、入力はvarchar(30)
ですが、bigint
のout of rangeエラーは許容されます。確実にvarchar(18)
を検討してください。または、単にtext
にして、無効な制限を削除します。
関数はVOLATILE
(デフォルト)であるため、PostgreSQLはcentral.cliente
のすべての行に対して同じ値を返すことを認識していないため、繰り返し評価されます。
ボラティリティをIMMUTABLE
に設定すると、PostgreSQLはそれを1回だけ評価する必要があることを認識します。
ALTER FUNCTION ext.uf_converte_numerico(varchar(30)) IMMUTABLE;
最初のケースでは、事前計算された値(v_cpf_numerico)
を使用しています。
2番目のケースでは、選択中にcentral.cliente
の各行の値が計算されます。