Eu tenho 2 funções semelhantes, maneiras diferentes resultam em grande diferença no desempenho.
A versão do PostgreSQL: 9.2.1.
Função 1
create or replace function func_1() returns text as
$$
declare
v_i integer;
v_md5 varchar;
begin
for v_i in 1..1000000 loop
v_md5:='a'|| v_i::character varying;
end loop;
return 'ok';
end;
$$
language plpgsql;
Função 2
create or replace function func_select() returns text as
$$
declare
v_i integer;
v_md5 varchar;
begin
for v_i in 1..1000000 loop
select 'a'|| v_i::character varying into v_md5;
end loop;
return 'ok';
end;
$$
language plpgsql;
Tempos de Função
francs=> \timing
Timing is on.
francs=> select func_1();
func_1
--------
ok
(1 row)
Time: 1467.231 ms
francs=> select func_1();
func_1
--------
ok
(1 row)
Time: 1383.424 ms
francs=> select func_select();
func_select
-------------
ok
(1 row)
Time: 22176.600 ms
francs=> select func_select();
func_select
-------------
ok
(1 row)
Time: 23265.755 ms
Do exposto, a função func_1()
leva apenas cerca de 1383 ms , mas a função func_select()
leva cerca de 23265 ms , alguém pode explicar isso?
O uso da instrução SQL pura no segundo loop faz com que o mecanismo de banco de dados compile o todo
select 'a'|| v_i::character varying into v_md5;
em cada iteração do loop antes de avaliá-lo, enquanto a atribuição de variável é analisada facilmente em instruções de baixo nível uma vez.Para melhor desempenho, você provavelmente pode usar
generate_series
como emNo meu teste, leva 1/6 do tempo da sua primeira implementação.
Adendo: btw, a principal diferença entre essas três implementações é quanto trabalho você delega em uma instrução para o back-end. Na minha solução você não faz um loop, então é 1 instrução, enquanto na sua segunda implementação você tem um loop que inclui um select (que é uma função complexa), e no seu primeiro exemplo você tem um loop que inclui uma atribuição (que é uma função simples). Isso explica a diferença.