質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

1361閲覧

railsチュートリアル サブセレクトでなぜ高速化するのか

suny

総合スコア48

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

1グッド

2クリップ

投稿2020/03/24 10:02

Ruby on rails 14章 サブセレクトでの質問です。

railsで

Micropost.where("user_id IN (:following_ids) OR user_id = :user_id", following_ids: following_ids, user_id: id)

よりも

following_ids = "SELECT followed_id FROM relationships WHERE follower_id = :user_id" Micropost.where("user_id IN (#{following_ids}) OR user_id = :user_id", user_id: id)

の方が効率的にデータを取り出せると書いてあったのですが理解しきれませんでした。

また、following_ids はrails内で作られたメソッドですが、このコードにクエリが代入?されている点もどういう動きをするのかが理解できませんでした。

噛み砕いて説明していただけたら嬉しいです。

SQLの知識はprogateのコースを1週したレベルです。よろしくお願いいたします。

shinoharat👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Railsが自動的に生成するfollowing_idsメソッドを呼ぶと、以下のようなSQLがデータベースに発行されます。

sql

1SELECT "users"."id" FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ?

その実行結果をもとに、Micropost.whereでメソッドが以下のようなSQLをデータベースに発行します。

sql

1SELECT "microposts".* FROM "microposts" WHERE (user_id IN (409608538,659682706) 2OR user_id = 762146111) ORDER BY "microposts"."created_at" DESC

ちなみに上の409608538,659682706の部分が最初のSQLで取得した実行結果です。
つまり、この場合はデータベースへの問い合わせが2回発生します。

一方で、

sql

1following_ids = "SELECT followed_id FROM relationships 2 WHERE follower_id = :user_id" 3Micropost.where("user_id IN (#{following_ids}) 4 OR user_id = :user_id", user_id: id)

と、書いた場合は次のようなSQLを1回発行するだけで同じ結果が得られます。

sql

1SELECT "microposts".* FROM "microposts" WHERE (user_id IN (SELECT followed_id FROM relationships 2WHERE follower_id = 762146111) 3OR user_id = 762146111) ORDER BY "microposts"."created_at" DESC

データベースへの問い合わせ処理は比較的コストが高いので、なるべく減らした方がパフォーマンス面で有利です。
よって、後者の方が効率的、ということになります。

別解

少し高等テクニックになりますが、次のように書く方法もあります。

ruby

1# following_idsはActiveRecord::Relationオブジェクトで、最終的にSQL(サブクエリ)に展開される 2following_ids = self.following.select(:id) 3Micropost.where("user_id IN (:following_ids) 4 OR user_id = :user_id", following_ids: following_ids, user_id: id)

こうすると次のようなSQLが1回発行されます。実行結果は同じです。

sql

1SELECT "microposts".* FROM "microposts" WHERE (user_id IN (SELECT "users"."id" FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = 762146111)

RailsやSQLに不慣れだとピンと来ないかもしれませんが、熟練者は堅牢性や再利用性の観点からなるべく手でSQLを書くよりもActiveRecordのクエリインターフェースを活用しようとするはずです。
知識として、こういった書き方があることも頭の片隅に置いておくと良いかもしれません。

投稿2020/05/09 01:33

jnchito

総合スコア357

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

suny

2020/06/01 05:17

teratailを見ない期間が長くなってしまい、返信が遅れてしまって申し訳ありません。 ありがとうございます! 別解も理解できました! また質問することがありましたら、よろしくお願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問