web-dev-qa-db-fra.com

Pourquoi le journal (le plus grand ()) est-il si lent?

Nous avons une requête complexe qui a été très lente. J'ai réussi à réduire la requête à une simple reproduction. Il semble que la combinaison de greatest et log en soit la cause, mais je ne comprends pas pourquoi.

Voici un exemple sql-fiddle complet pour exécuter les requêtes - et vous pouvez également View the execution Plans Des requêtes (appuyez sur le lien en bas du résultat de la requête sur le sql- page violon)

Voici donc la requête lente :

select count(value)
from (
         SELECT  log(greatest(1e-9, x)) as value
         from (select generate_series(1, 20000, 1) as x) as d
     ) t;

Nous générons simplement une série de nombres de 20k et utilisons log(greatest()). Cette requête prend environ 1,5 secondes.

Je pensais que le calcul du journal peut prendre du temps, mais la requête suivante est également rapide ( ~ 5ms ):

select count(value)
from (
         SELECT  log(x) as value
         from (select generate_series(1, 20000, 1) as x) as d
     ) t;

Tout comme un test, j'ai échangé greatest et log - c'est aussi rapide ( ~ 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;

Les QUERY PLANS Pour les 3 requêtes sont les mêmes:

Aggregate (cost=22.51..22.52 rows=1 width=8)
-> Result (cost=0.00..5.01 rows=1000 width=4)

Quelqu'un peut-il expliquer pourquoi la première requête est si lente - et peut-être que quelqu'un connaît une solution?

Plus de détails

plates-formes lentes

J'obtiens des résultats similaires sur tous ces éléments (la première requête est d'une amplitude plus lente):

  • SQL Fiddle utilise pg 9.6
  • mon PC local avec des résultats similaires: Win10 64bit, pg 11.5 fonctionnant dans Docker
  • serveur distant: Ubuntu 18.04 64 bits exécutant pg 11.5 dans Docker
  • rextester.com

compter

Lorsque je change count(value) en count(*) ou count(1) (numéro un) la requête est rapide

  • mais cela ne m'aide pas car la requête de production n'inclut même pas de décompte
  • de toute façon, je me demande pourquoi il y a une différence dans ce cas (il n'y a pas de valeurs nulles dans les données)
3
TmTron

Vous invoquez deux fonctions de journal différentes ici: log(numeric,numeric) et log(double precision), et la première est beaucoup plus lente que la seconde.

Remarquez comment les fonctions d'appel diffèrent dans EXPLAIN (ANALYZE, VERBOSE) ci-dessous, exécuté avec PostgreSQL 11.5 (Linux Ubuntu):

Version lente:

explain (analyze, verbose) select count(value)
from (
         SELECT  log(greatest(1e-9, x)) as value
         from (select generate_series(1, 20000, 1) as x) as d
     ) t;
                                              QUERY PLAN                                               
-------------------------------------------------------------------------------------------------------
 Aggregate  (cost=25.02..25.03 rows=1 width=8) (actual time=1174.349..1174.349 rows=1 loops=1)
   Output: count(log('10'::numeric, GREATEST(0.000000001, ((generate_series(1, 20000, 1)))::numeric)))
   ->  ProjectSet  (cost=0.00..5.02 rows=1000 width=4) (actual time=0.004..1.310 rows=20000 loops=1)
         Output: generate_series(1, 20000, 1)
         ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1)
 Planning Time: 0.123 ms
 Execution Time: 1174.385 ms

Version rapide:

explain (analyze, verbose) select count(value)
from (
         SELECT  log(greatest(1e-9::float, x)) as value
         from (select generate_series(1, 20000, 1) as x) as d
     ) t;
                                                  QUERY PLAN                                                   
---------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=25.02..25.03 rows=1 width=8) (actual time=6.693..6.693 rows=1 loops=1)
   Output: count(log(GREATEST('1e-09'::double precision, ((generate_series(1, 20000, 1)))::double precision)))
   ->  ProjectSet  (cost=0.00..5.02 rows=1000 width=4) (actual time=0.004..2.561 rows=20000 loops=1)
         Output: generate_series(1, 20000, 1)
         ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1)
 Planning Time: 0.096 ms
 Execution Time: 6.731 ms

greatest() n'est pas responsable: si l'on considère la requête avec juste log(x), si vous transtypez x en numeric ce sera aussi lent avec ou sans greatest().

6
Daniel Vérité