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も数件しかないことが分かる。とプランナが解釈すると思ってたけどそうではなかったみたい。