eityansメモ

eityansメモ

ゆるくやっていきます

記事一覧RSS

group_by を group + array_agg で高速化する(PostgreSQL)

こういうパフォーマンス改善もあるよメモ


ユーザーと記事があり、ユーザーは記事をお気に入りできる。お気に入りには種類がある。お気に入りの種類ごとに記事のidの配列を取得するような処理を考える。

1{
2  "like_name_1" => [1,2,3,4],
3  "like_name_2" => [5,6,7,8],
4}

最終的にはこんな感じのデータを取りたい

group_by を使う

1Like
2  .where(user_id: user.id)
3  .select(:name, :post_id)
4  .group_by(&:name)
5  .transform_values { |v| v.pluck(:post_id) }

group_byでDBの結果を取得しtransform_values以降をRailsで処理することになる。数が多い場合はパフォーマンスが気になる

group + array_aggを使う

集約関数のarray_aggを使う

NULLも含めてすべての入力値を収集して配列に格納します。

1Like
2  .where(user_id: user.id)
3  .group(:name)
4  .select(:name, "array_agg(post_id) as post_ids")
5  .to_h{ |g| [g.name, g.post_ids] }

こうすることでgroupの処理をDB側に寄せることができる。ただし、可読性の低下や、PostgreSQLに依存した実装になってしまうためそのあたりのデメリットは考慮すること。


ちなみにMySQLの場合はGROUP_CONCATが使えそう