Esta é uma continuação de uma pergunta que fiz sobre a melhor maneira de calcular estatísticas em uma lista de linhas exclusivas por coluna, que pode ser encontrada aqui (junto com o esquema da tabela)
Eu tenho uma tabela que contém milhões de linhas de dados de estoque e quero calcular agregados personalizados nessas linhas. A ideia é anexar cada valor de entrada na função de transição de estado. Então o finalfunc calculará o número neste array. O agregado é definido como:
create or replace aggregate RSI(input float8) (
SFUNC=tech_float8_accum,
STYPE=float8[],
FINALFUNC=RSI_Func
);
Onde implementei ingenuamente a função de agregação de array no plpython:
-- Append the next input value to the state array
CREATE OR REPLACE function tech_float8_accum(agg float8[], input float8)
returns float8[]
AS $$
return agg + [input] if agg != None else [input]
$$ LANGUAGE plpython3u;
O finalfunc também é escrito em plpython e, por experiência própria, é bastante rápido, pelo menos fora do contexto de banco de dados, já que usa Cython nos bastidores.
CREATE OR REPLACE FUNCTION RSI_Func(input float8[], out val float8)
AS $$
import talib
import numpy as np
cd=np.array(input)
rsi = talib.RSI(cd)
return rsi[-1]
$$ LANGUAGE plpython3u;
Uso atual:
select "security", RSI(ordered.close)
from (
select "security", close
from stocks_data.bars
where "timeframe" = '1d'
and "timestamp" >= '2022-11-02'::timestamp
order by "timestamp" asc
) as ordered
group by ordered.security;
Isso leva aproximadamente 3 minutos , quando na realidade preciso de algo em torno de 3 segundos ou menos, como a função AVG integrada oferece.
Há algo que eu possa fazer para melhorar drasticamente essa abordagem ou devo adotar outra abordagem? São muitos dados para trazer na memória.