2017-07-04 6 views
2

私はこの機能を持っていて、動作していれば、最新のbレコードが得られます。Postgres 9.6の機能がまっすぐなSQLと比較してパフォーマンスが悪い

create or replace function most_recent_b(the_a a) returns b as $$ 
    select distinct on (c.a_id) b.* 
    from c 
    join b on b.c_id = c.id 
    where c.a_id = the_a.id 
    order by c.a_id, b.date desc 
$$ language sql stable; 

これは〜5000msの実データで実行されます。 V.S. 500msの

create or replace function most_recent_b(the_a a) returns b as $$ 
    select distinct on (c.a_id) b.* 
    from c 
    join b on b.c_id = c.id 
    where c.a_id = 1347 
    order by c.a_id, b.date desc 
$$ language sql stable; 

で実行以下は、唯一の違いは、私はハード値1347の代わりに、そののparam値を使用してa.idをコード化されたことであること。

も機能せずに、このクエリを実行するには、また、私は他の場所で提案参照機能の結果に失敗問い合わせプランナは、右の私には適用されない必要がありますので、私は、周りの500msの

私は、PostgreSQL 9.6を実行しているスピード与えますか?

私はそれが問題であるクエリ自体ではないことを確信しています。これは私の3番目の反復であり、この結果を得るためのさまざまなテクニックは、関数内で同じ速度で同じ結果になります。

(それが正確だった定数

Unique (cost=60.88..60.89 rows=3 width=463) (actual time=520.117..520.122 rows=1 loops=1) 
    Buffers: shared hit=14555 
    -> Sort (cost=60.88..60.89 rows=3 width=463) (actual time=520.116..520.120 rows=9 loops=1) 
     Sort Key: b.date DESC 
     Sort Method: quicksort Memory: 28kB 
     Buffers: shared hit=14555 
     -> Hash Join (cost=13.71..60.86 rows=3 width=463) (actual time=386.848..520.083 rows=9 loops=1) 
       Hash Cond: (b.c_id = c.id) 
       Buffers: shared hit=14555 
       -> Seq Scan on b (cost=0.00..46.38 rows=54 width=459) (actual time=25.362..519.140 rows=51 loops=1) 
        Filter: b_can_view(b.*) 
        Rows Removed by Filter: 112 
        Buffers: shared hit=14530 
       -> Hash (cost=13.67..13.67 rows=3 width=8) (actual time=0.880..0.880 rows=10 loops=1) 
        Buckets: 1024 Batches: 1 Memory Usage: 9kB 
        Buffers: shared hit=25 
        -> Subquery Scan on c (cost=4.21..13.67 rows=3 width=8) (actual time=0.222..0.872 rows=10 loops=1) 
          Buffers: shared hit=25 
          -> Bitmap Heap Scan on c c_1 (cost=4.21..13.64 rows=3 width=2276) (actual time=0.221..0.863 rows=10 loops=1) 
           Recheck Cond: (a_id = 1347) 
           Filter: c_can_view(c_1.*) 
           Heap Blocks: exact=4 
           Buffers: shared hit=25 
           -> Bitmap Index Scan on c_a_id_c_number_idx (cost=0.00..4.20 rows=8 width=0) (actual time=0.007..0.007 rows=10 loops=1) 
             Index Cond: (a_id = 1347) 
             Buffers: shared hit=1 
Execution time: 520.256 ms 

で(、BUFFERSをANALYZE)説明し、これはパラメータが渡されると、6回を実行した後の結果であるの

@ローレンツ-ALBE結果によって要求されます予測通りに6回))
遅いクエリ。

Unique (cost=57.07..57.07 rows=1 width=463) (actual time=5040.237..5040.243 rows=1 loops=1) 
    Buffers: shared hit=145325 
    -> Sort (cost=57.07..57.07 rows=1 width=463) (actual time=5040.237..5040.240 rows=9 loops=1) 
     Sort Key: b.date DESC 
     Sort Method: quicksort Memory: 28kB 
     Buffers: shared hit=145325 
     -> Nested Loop (cost=0.14..57.06 rows=1 width=463) (actual time=912.354..5040.195 rows=9 loops=1) 
       Join Filter: (c.id = b.c_id) 
       Rows Removed by Join Filter: 501 
       Buffers: shared hit=145325 
       -> Index Scan using c_a_id_idx on c (cost=0.14..9.45 rows=1 width=2276) (actual time=0.378..1.171 rows=10 loops=1) 
        Index Cond: (a_id = $1) 
        Filter: c_can_view(c.*) 
        Buffers: shared hit=25 
       -> Seq Scan on b (cost=0.00..46.38 rows=54 width=459) (actual time=24.842..503.854 rows=51 loops=10) 
        Filter: b_can_view(b.*) 
        Rows Removed by Filter: 112 
        Buffers: shared hit=145300 
Execution time: 5040.375 ms 

その私はいくつかの厳しい行レベルのセキュリティが関係しており、私はこれらのクエリの両方が遅い、しかし、一方が他方よりも10倍遅いですなぜこれがある疑いがあることは注目に値します。

元のテーブル名を変更しました。検索と置換がうまくいけばうれしいです。

+1

なぜ関数 'most_recent_b(the_a_id int)が' b'を返すのですか? –

+0

@VaoTsunどのparam型でも同じ減速します。 – Tim

+0

私はこの問題にぶつかるかもしれないと思うhttps://www.postgresql.org/message-id/flat/[email protected]#[email protected] – Tim

答えて

2

クエリ実行の高価な部分は、フィルタb_can_view(b.*)です。これは、行レベルのセキュリティ定義から取得する必要があります。

高速実行:

Seq Scan on b (cost=0.00..46.38 rows=54 width=459) 
       (actual time=25.362..519.140 rows=51 loops=1) 
    Filter: b_can_view(b.*) 
    Rows Removed by Filter: 112 
    Buffers: shared hit=14530 

遅い実行:

Seq Scan on b (cost=0.00..46.38 rows=54 width=459) 
       (actual time=24.842..503.854 rows=51 loops=10) 
    Filter: b_can_view(b.*) 
    Rows Removed by Filter: 112 
    Buffers: shared hit=145300 

差は、スキャンが遅い場合(loops=10)で10回実行されることがあり、10倍のデータに触れますブロック。

一般プランを使用すると、を満たす行の数が実際の値が平均よりも多い1347であることがわかっていないため、PostgreSQLはその行の数を過小評価します。

PostgreSQLでは、cの行が最大で1つしかないと考えているため、内側のbというシーケンシャルスキャンでネストループ結合を選択します。

今、二つの問題がコンバイン:機能b_can_viewを呼び出す

  1. は、163行のシーケンシャルスキャンがかかる0.5秒を占める、(PostgreSQLは知りません)行当たり3以上ミリ秒かかります。

  2. 予測される1の代わりにcに実際に10行があるため、テーブルbが10回スキャンされ、クエリの実行時間が5秒になります。

あなたは何ができますか?

  • b_can_viewがどれほど高価であるかをPostgreSQLに伝えます。 ALTER TABLEを使用して、現実を反映するためにその機能のCOSTを1000または10000に設定します。とにかくPostgreSQLは単一シーケンシャルスキャンを実行しなければならないと考えているので、それだけではより速いプランを得るには不十分ですが、オプティマイザに正しいデータを与えることは良いことです。

  • b(c_id)にインデックスを作成します。これにより、PostgreSQLはbという逐次スキャンを避けることができます。これは、機能がどれだけ高価であるかを認識した後に行うことになります。

また、b_can_viewを安くしてみてください。それはあなたの経験をはるかに良くするでしょう。

+0

ありがとう!元の質問を更新しました。 – Tim

+0

私は追加情報に答えを適用しました。 –

関連する問題