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

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

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

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Ruby on Rails

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

Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

Q&A

解決済

3回答

593閲覧

sqlのorderbyによる負荷(rails)

domidomi

総合スコア34

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Ruby on Rails

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

Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

0グッド

1クリップ

投稿2018/03/12 02:18

編集2018/03/12 02:23

##疑問

1.@hoge = Model.order("fuga DESC").take(5)で発行されるSELECT "models".* FROM "models" ORDER BY fuga DESC LIMIT ? [["LIMIT", 5]]をした時レコード数が莫大な場合の負荷は大きいのか?(5つ取り出しているだけだから特に負荷はないのか?)

2.負荷がかなり大きいのならば、ランキングのようにある属性の上位5つを取ってくる最適なクエリはどのように書けばよいのか?

##考え流れ

@hoge = Model.order("fuga DESC").take(5)
のようにactive_recordで指定してモデルを並べ替えてそのうちの5つをとってくるという文を書きました。そのため

SELECT "models".* FROM "models" ORDER BY fuga DESC LIMIT ? [["LIMIT", 5]]
のようなSQL文が発行されるかと思います。

これは、一度modelテーブルのレコードをすべて参照して並び替えてそのうちの5個をとってきているとおもっています。

SQL自体は1文で簡単なものかと思うのですが、レコード数が10万など(とっても多く)なった場合レコードをすべて参照しての部分でかなりの負荷がでてしまうのでは?と思いました。

しかし何かの項目上位5つを取り出す時、この負荷は避けられないきがしてしまいます。

実行環境はrailsです。
お時間あるときにでもよろしくお願いいたします。

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

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

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

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

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

guest

回答3

0

ベストアンサー

環境(サーバのスペック)や設定(my.cnf)にもよるので10万件とか20万件でどうなるかというのは、実際にお使いの環境で試したほうが早いです。
ぜひ試してみてください。

昔の偉い人がいった言葉で「推測するな計測せよ」というのがあるらしいんですけど、まさにその通りで、まずは試して速度や負荷を計ってみてはどうでしょうか?

20万件のレコードを入れるコードは、お分かりだと思いますが一応こんな感じですね。

ruby

1# rubyは数値リテラルにアンダースコアが使えるので見やすい位置で 2# アンダースコアを入れると分かりやすいです 3total = 200_000 4total.times.each do |n| 5 attrs = { 6 モデルのフィールドの設定 7 } 8 model = Model.create!(attrs) 9 puts "#{n}/#{total}: #{model.inspect}" 10end

ランキングについては、リアルタイムである必要がなく、
前日のデータをもとにランキングを決めるという事で良い場合は、
あらかじめランキングテーブルを用意して、
バッチで集計した結果を入れておくという方法が割とメジャーだと思います。

投稿2018/03/12 02:47

mingos

総合スコア4025

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

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

domidomi

2018/03/12 06:57

回答ありがとうございます。 >あらかじめランキングテーブルを用意して、バッチで集計した結果を入れておく こんなメジャーそうな発想すら出てきておりませんでした。 〇万件インサートは以前本番環境に10万件いっきにいれてためそうとしたところ、全然入力が終了しなくてあきらめてしまっていたので、やることすらしませんでした申し訳ないです。 >推測するな計測せよ 大事な事ですね、ありがとうございます
guest

0

大抵のDBエンジンではorder by を前提にシステムが構築されているので
おそらくorder byが一番はやい処理になります。
とはいえexplainなどでチェックするとfilesortなどで実行されるケースが
多いので、完全な効率化がなされることはないでしょう
しかしランキング処理もしくはDBごとに用意されたランキング系の関数は
ロジック的にコストが高いので、それにくらべればorder byの方がマシだと
思います。
(実際にはテストをして効率が良い方を採用することになるでしょう)

投稿2018/03/12 02:36

yambejp

総合スコア114779

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

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

domidomi

2018/03/12 06:54

回答ありがとうございます データベース側もさすがに大きくなることを見越して作られているという事ですね
guest

0

全てのDBにあてはまるかはわかりませんが、少なくともMySQLであれば、カラム「fuga」にインデックスを貼れば、テーブルを全件読み込まずに処理されるのではないでしょうか。

投稿2018/03/12 09:31

編集2018/03/12 22:39
bassbone

総合スコア767

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問