Temos algumas consultas complexas que foram muito lentas. Consegui reduzir a consulta a uma simples reprodução. Parece que a combinação de greatest
e log
é a causa, mas não entendo o porquê.
Aqui está um exemplo completo do sql-fiddle para executar as consultas - e você também pode View the execution Plans
das consultas (pressione o link na parte inferior do resultado da consulta na página do sql-fiddle)
Então aqui está a consulta lenta :
select count(value)
from (
SELECT log(greatest(1e-9, x)) as value
from (select generate_series(1, 20000, 1) as x) as d
) t;
Nós apenas geramos uma série de 20k números e usamos log(greatest())
. Essa consulta leva cerca de 1,5 segundos.
Achei que calcular o log pode demorar, mas a consulta a seguir também é rápida ( ~5ms ):
select count(value)
from (
SELECT log(x) as value
from (select generate_series(1, 20000, 1) as x) as d
) t;
Apenas como teste eu troquei greatest
e log
- isso também é rápido ( ~5ms ):
select count(value)
from (
SELECT greatest(1e-9, log(x)) as value
from (select generate_series(1, 20000, 1) as x) as d
) t;
O QUERY PLANS
para todas as 3 consultas são os mesmos:
Aggregate (cost=22.51..22.52 rows=1 width=8)
-> Result (cost=0.00..5.01 rows=1000 width=4)
Alguém pode explicar por que a primeira consulta é tão lenta - e talvez alguém conheça uma solução alternativa?
Mais detalhes
plataformas lentas
Eu recebo resultados semelhantes em todos eles (a primeira consulta é uma magnitude mais lenta):
- SQL Fiddle usa página 9.6
- meu PC local com resultados semelhantes: Win10 64bit, pg 11.5 rodando no Docker
- servidor remoto: Ubuntu 18.04 64 bits executando pg 11.5 no Docker
- rextester. com
- consulta lenta ~ 3 segundos
- consulta rápida ~ 0,5 segundos
contar
Quando mudo count(value)
para count(*)
ou count(1)
(número um) a consulta é rápida
- mas isso não me ajuda porque a consulta de produção nem inclui uma contagem
- de qualquer forma, eu me pergunto por que há uma diferença neste caso (não há valores nulos nos dados)
Você está invocando duas funções de log diferentes aqui:
log(numeric,numeric)
elog(double precision)
, e a primeira é muito mais lenta que a segunda.Observe como a chamada das funções difere no EXPLAIN (ANALYZE, VERBOSE) abaixo, executado com PostgreSQL 11.5 (Linux Ubuntu):
Versão lenta:
Versão rápida:
greatest()
não é responsável: considerando a consulta com justlog(x)
, se você converterx
paranumeric
ela será tão lento com ou semgreatest()
.