ログ日記

作業ログと日記とメモ

PostgreSQLでビューを使う時の最適化

ちょっと簡単なサンプルが思い付かないけど。
joinが大量にある巨大なビューから少ない件数のデータを取得する場合。

ビュー単体でselectしたら全てインデックススキャンになるようにしていて

  select *
  from large_large_view
  where large_large_view.post_id in (123, 456,789)

これは高速になるようにしていた。
しかし

select large_view.*
from (
  select post_id
  from fav
  where user_id = ?
) as fav
join lateral (
  select *
  from large_large_view
  where large_large_view.post_id = fav.post_id
) as large_view on true

joinすると遅い。
何故か 結合条件で絞り込む前にビューの深いところでseq scanが走っている。
viewとjoinで遅いというのは都市伝説ではなかった模様。

ビューをバラして一段階層を上げてjoinすれば速いし、ビューにしなくても join (select ...) と入れ子にすると遅かった。
lateral効いてないっぽい。


それで一度は諦めていたんだけど、何故か他の箇所で速く動いているものがあった。
そっちの方はよく見ると

select large_view.*
from (
  select post_id
  from fav
  where user_id = ?
) as fav
join lateral (
  select *
  from large_large_view
  where large_large_view.post_id = fav.post_id
  limit 15 -- <= 制限
) as large_view on true

数件で収まらない可能性があるからlimit付けてた。
そうするとプランがガラッと変わってjoinを使わないときと同等になるようだった。
favの方のインデックスでプランナはfavが数件しか無いことが分かり、large_large_viewも数件しかないことが分かる。とプランナが解釈すると思ってたけどそうではなかったみたい。