web-dev-qa-db-ja.com

なぜlog(greatest())はとても遅いのですか?

非常に遅い複雑なクエリがいくつかあります。クエリを単純な複製に縮小することができました。 greatestlogの組み合わせが原因のようですが、理由がわかりません。

完全な sql-fiddleの例 でクエリを実行します-クエリの_View the execution Plans_も実行できます(sql-fiddleページのクエリ結果の下部にあるリンクを押してください)

slowクエリは次のとおりです。

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

一連の20kの数値を生成し、log(greatest())を使用します。このクエリには約1.5秒かかります。

ログの計算には時間がかかると思いましたが、次のクエリも高速です(〜5ms):

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

テストと同じようにgreatestlogを交換しました-これも高速です(〜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;
_

3つのクエリすべての_QUERY PLANS_は同じです。

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

最初のクエリが非常に遅い理由を誰かが説明できますか-おそらく誰かが回避策を知っていますか?

もっと詳しく

遅いプラットフォーム

これらすべてで同様の結果が得られます(最初のクエリは速度が遅くなります)。

  • SQL Fiddleはpg 9.6を使用します
  • 私のローカルPCで同様の結果:Dockerで実行されているWin10 64ビット、pg 11.5
  • リモートサーバー:Dockerでpg 11.5を実行しているUbuntu 18.04 64ビット
  • rextester.com

カウント

count(value)count(*)またはcount(1)(1番)に変更すると、クエリが高速になります

  • しかし、生産クエリにはカウントも含まれていないため、これは私には役立ちません
  • とにかく、なぜこの場合に違いがあるのでしょうか(データにnull値はありません)。
3
TmTron

ここでは、2つの異なるログ関数log(numeric,numeric)log(double precision)を呼び出しています。最初の関数は2番目の関数よりもはるかに低速です。

以下のEXPLAIN(ANALYZE、VERBOSE)で関数呼び出しがどのように異なるか、PostgreSQL 11.5(Linux Ubuntu)で実行することに注意してください。

遅いバージョン:

_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
_

高速バージョン:

_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()は責任を負いません。log(x)のみを使用したクエリを検討すると、xnumericにキャストすると、greatest()

6
Daniel Vérité