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

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

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

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

6回答

918閲覧

12テーブルをINNER JOINしているSQL文(コードあり)の速度改善をしたいです。LEFT OUTER JOINに変えたりしておりますが、改善につながりません。

qaz3330

総合スコア113

MySQL

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2017/07/29 11:37

次のようなSQL文があります。
こちらのSQLでは、INNER JOINしているテーブル及び、WHERE文で対象としているテーブルは、2つしかありません。
これでしたら10秒ほどで、集計が完了します。

しかし、今回の要件上、INNER JOINするテーブル数は、12個あり、
同様にINNER JOINとWHERE文を追加していき実行すると、1時間以上かかってしまいます。

sql

1 2SELECT artists.user_id, artists.staff_id, 3Sum(events.sum),\ 4Sum(goods.sum),\ 5FROM artists\ 6INNER JOIN `events` ON `artists`.`id` = `events`.`artist_id`\ 7INNER JOIN `goods` ON `artists`.`id` = `goods`.`artist_id`\ 8WHERE (`events`.`created_at` BETWEEN '2017-01-01' AND '2017-07-30')\ 9AND (`goods`.`created_at` BETWEEN '2017-01-01' AND '2017-07-30')\ 10GROUP BY artists.user_id, artists.staff_id; 11 12

SQLの速度改善をしたいのですが、これ以上絞り込む条件がないため、
SQL文の見直しにより、改善できる方法を探しております。

尚、バッチ処理にするという案は今回の要件上NGでした。

生のSQL文で記述しておりますが、実際はRuby on Railsのアプリケーション上で実行します。
その為、非同期処理というのも模索しておりますが、今回、集計した結果をDBにINSERTするため、
非同期処理にすると、本来データが入ってほしいレコードにデータが入らないという恐れを懸念しております。

INNER JOIN を LEFT OUTER JOIN にしたり等、不勉強ながら試行錯誤しておりますが、なかなか改善につながりません。

理想は1~2分で完了してほしいです。

また、この集計処理は、期間を変えて実行することはあっても、同じSQL文を何度も使うということはないので、
クエリキャッシュをするというのもあまり意味がないと思っております。

また、外部キー周りにindexキーはつけております。

宜しくお願い致します。

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

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

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

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

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

miyahan

2017/07/29 12:16

実際に遅くなっているクエリと各テーブルのスキーマがわからないとと答えようがないです。
guest

回答6

0

まずやるべきことは、EXPLAINです。

Railsのコンソールから(リレーション).explainでも出ますが、ときどき必要な情報が取れないこともあって、(リレーション).to_sqlとして生成したSQL文を、EXPLAIN (SQL文)のようにしてSQLコンソールから実行しましょう。

多くの場合、

  • インデックスで絞れないテーブルスキャンの発生
  • 結合条件がうまく効かず、爆発的な行数の一時テーブルを生成している

などの問題が見つかるかと思います。

投稿2017/07/29 12:45

編集2017/07/29 12:46
maisumakun

総合スコア145183

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

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

0

ベストアンサー

最近、似たような形のSQLチューニングの仕事しました。
(同じ人が作ったSQLですか?と思ってしまうくらい似てます。
元々1時間以上かかる処理で、その方も理想は1~2分での完了が希望で、
ダメならバッチ処理を検討してました。)

その仕事では、意図する抽出結果のSQLを作成して、
1秒以内に終わる処理にチューニングしたので、
ちゃんとチューニングしてあげれば、
恐らく数秒程度で終わるSQLになります。

あと、記載されているSQLだと、抽出結果が意図しない結果になる可能性が非常に高いです。
artistsテーブルの1行に対して、
events.sumとgoods.sumがそれぞれ複数存在する場合を考慮していないSQLです。

explainをすると、おそらく「Block Nested Loop」あたりが出てくると思いますが、
まずは、チューニングの前に、意図した抽出結果になるSQLを作ることをお勧めします。

投稿2017/08/01 12:46

tomari_perform

総合スコア760

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

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

0

処理時間以前にartist別に発生するeventsやgoodsなどの12のアイテムが必ず発生するとは思えず、innerではなくouterで結合しないとよろしくないのではないでしょうか。

この前提をもとに組み替えてみました

SQL

1select artists.*, events.item_sum, goods.item_sum 2from 3 (select user_id, staff_id from artists group by user_id, staff_id) artists 4 left join ( 5 select user_id, staff_id, sum(item.sum) item_sum 6 from artists inner join events as item on artists.id=item.artist_id 7 where created_at between '2017-01-01' and '2017-07-30' 8 group by user_id, staff_id 9 ) events 10 on artists.user_id=events.user_id and artists.staff_id=events.staff_id 11 left join ( 12 select user_id, staff_id, sum(item.sum) item_sum 13 from artists inner join goods as item on artists.id=item.artist_id 14 where created_at between '2017-01-01' and '2017-07-30' 15 group by user_id, staff_id 16 ) goods 17 on artists.user_id=goods.user_id and artists.staff_id=goods.staff_id 18

キー構成やインデックスの状況が分からないので何とも言えませんが、
少なくともアイテムごとに独立しているので、アイテムの数と処理時間は比例したものになるのではないかと思います。

ここでは以下のインデックスを想定しています。
artists(user_id, staff_id, artist_id)
events や goodsなど(created_at, artist_id)

何れにせよ、sql文だけではなく、キー構成とインデックスおよび実行計画の結果も提示して、どこにネックがあるかを質問した方が的確なアドバイスが付くと思います。

投稿2017/07/30 07:00

編集2017/07/30 07:02
sazi

総合スコア25173

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

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

0

というか
artists eventsの内部結合
artists goodsの内部結合
の2回クエリを実行すべきで
artists, events, goods, を全部内部結合するのはちょっと違うような?

たぶん別々で集計したほうがいいですよ。

シングルスレッドで順次実行したらどれくらいかかりますか。
また マルチスレッドで集計するのも全然有りです。
全部のスレッドが完了するまで待機する というマルチスレッドの作法に則り
全スレッドが完了したら取得した集計データをInsertすればよいです。

投稿2017/07/29 17:36

Tak1016

総合スコア1408

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

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

0

BETWEEN で指定している created_at にindex設定すればいいのでは?

投稿2017/07/29 17:26

Tak1016

総合スコア1408

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

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

0

artistsテーブルのuser_idやstuff_idとidの整合性がとれてないのでは?
すべてinner joinしてから集計しないでも個々に集計してから
くっつけたほうが速いかもしれませんね
具体的なサンプルを提示されないと具体的な高速化については言及できないと思います

投稿2017/07/31 01:24

yambejp

総合スコア114779

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問