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

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

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

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

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

8回答

3946閲覧

データ抽出バッチ処理 速度改善

whxtna

総合スコア57

MySQL

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

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2017/08/21 05:19

6万件の会員データ(会員テーブル)があったとして、
その中から特定の条件の会員情報を3万件程抜き出すバッチ処理があった場合。
バッチ処理内のデータ抽出処理の箇所は下記①・②とでどちらが速度的に早いのでしょうか?


SQL文にて
SELECT * FROM 会員テーブル WHERE user_id in (特定条件下の会員リスト)
にて一気に抽出する。


SELECT * FROM 会員テーブル
にて一旦全会員分のデータ抽出後に、PHPのプログラムにてforeachでループさせて、
特定条件下の会員を絞り込む。

元々は①だったのですが、処理時間がかかり過ぎていたので、

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

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

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

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

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

guest

回答8

0

ベストアンサー

DB側でできることはDB側でやるのが原則ですが、50%取り出すなら微妙ですね。構成とデータ量とクエリによっては全件取り出してプログラム側で処理する方が良いかもしれません。

MySQL5.6以前にはINでサブクエリを使うと極端に遅いという癖がありました。こういうこともあるので、何が遅いかは必ず確認した方が良いです。

EXPLAINを使うとSQLの実行計画を確認できます。
https://dev.mysql.com/doc/refman/5.6/ja/execution-plan-information.html

闇雲にインデックスを張るとかえって性能が低下する場合があります。バッチ側で変化がなくても、他のアプリケーションで影響がでることもあります。インデックスがないことが原因だということを確認してからにしましょう

投稿2017/08/21 06:00

suzukis

総合スコア1449

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

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

whxtna

2017/08/22 02:20

ご回答ありがとうございます。 自分も”MySQL5.6以前にはINでサブクエリを使うと極端に遅いという癖”こちらを懸念しておりました。 回答いただいている内容を参考にし、再確認しようと思います。
guest

0

3万件/6万件 だとインデックスの効果はあまりないでしょうね。

4.正攻法として、ボトルネックを探して改善していく。
ネットワークが遅いのか、I/O処理が遅いのか、実行時(サーバ側)の問題かなどで対処法は全然違ってきます。

5.特定条件下の会員リストを持つテーブルを作る(user_idのみのテーブル)
特定条件下の会員リストの変更頻度が少なければこれが最速になりそうです。

SQL

1/* 2DELETE FROM user_id_table; 3INSERT INTO user_id_table(user_id) VALUES (2),(3),(6),(8) 4*/ 5SELECT 会員テーブル.* FROM 会員テーブル INNER JOIN user_id_table ON 会員テーブル.user_id = user_id_table.user_id

6.可能であれば、会員テーブルに出力フラグのカラムを追加する

投稿2017/08/21 07:17

hihijiji

総合スコア4150

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

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

whxtna

2017/08/22 02:29

ご回答ありがとうございます。参考にさせていただきます。
guest

0

テンポラリテーブルをつくり、検索したいidを流し込んでおいて
inner joinで処理してはいかがでしょうか?
もちろん適正なインデックスは付加する必要はあると思います

また、そのid群が再利用する可能性が高いなら、適当な出力用のフラグを
新たにカラムとして登録しておけば良いと思います

投稿2017/08/21 05:41

編集2017/08/21 05:42
yambejp

総合スコア114784

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

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

whxtna

2017/08/22 02:18

ご回答ありがとうございます。参考にさせていただきます。
guest

0

皆さんの記載の通り、どちらが重たいのか確認したほうが良さそうですね。

SQL

1(a).SELECT * FROM 会員テーブル WHERE user_id in (特定条件下の会員リスト) 2(b).特定条件下の会員リスト

・INからEXISTSに変更してみる
・(a)は50%とのことなので、インデックス効果が微妙かと。
・(b)は改善の余地はありそうです。抽出条件に沿ったインデックスを付与するなり、一時テーブルを作って、JOINしてみたらいかがでしょうか。
・列指定を[*]としているのであれば、抽出項目を必要分にしてデータ量を減らすとかでしょうか。

投稿2017/08/21 11:58

roast_chicken

総合スコア254

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

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

whxtna

2017/08/22 02:33

ご回答ありがとうございます。参考にさせていただきます。
guest

0

一般に、インデックスが有効に利くのは全データに対するヒット率が10%を切るあたりではないかと思います。
インデックス検索+インデックスで見つけたデータにランダムアクセス、という処理が、I/O としてみた場合に単純にI/O回数が多く、遅くなるからです(SSD であってもシーケンシャルアクセスよりランダムアクセスが遅いのは言わずもがな)。
また、SELECT 対象の列にも依存します。仮に対象列の情報がすべてインデックスの構成要素であるならば、実データにアクセスする必要がない(インデックスだけ見ればよい)ので、早くなります。

全体の半分が対象となると、実際の抽出 SQL でも、全件取り出して要らないものを捨てている可能性が高いです。
※全件を、それも sort なしで取り出すということは、DB からみるとレコードを記録しているファイルをシーケンシャルアクセスすればよいことになるため、インデックス経由のランダムアクセスより早くなります

投稿2017/08/21 11:29

tacsheaven

総合スコア13703

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

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

whxtna

2017/08/22 02:30

ご回答ありがとうございます。参考にさせていただきます。
guest

0

①で取り出す時間と、全件取り出す時間は、どの程度なのでしょうか?

全件取り出す時間に対して、①の方が遅いというなら、①を改善する方法と②のどちらの方法を取るにせよ改善を見込む余地はありますが、そうでないなら、約半分のデータが対象ということなので、改善は微妙ですね。

投稿2017/08/21 06:16

編集2017/08/21 10:57
sazi

総合スコア25173

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

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

whxtna

2017/08/22 02:29

ご回答ありがとうございます。 limitを1000にして検証した結果、①が6.0sec、全件抽出が0.9secぐらいになります。
guest

0

一般的には①だと思うのですが、処理時間がかかりすぎている理由が良く分かりません。

  • user_idにインデックスを作成する
  • (特定条件下の会員リストを別のSQLで取得しているのであれば)条件に使用するカラムにインデックスを作成する

などの方法でチューニングが可能かと思います。
インデックス作成は下記のようにします。

CREATE INDEX index_name ON table_name

投稿2017/08/21 05:29

tsuemura

総合スコア663

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

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

whxtna

2017/08/22 02:18

ご回答ありがとうございます。参考にさせていただきます。
guest

0

そのバッチって本当にそのSQLが遅いですか。
ログやEXPLAINを確認した結果でしょうか。

in句を利用しているのであれば、
PHP側で3万件のリストを用意している処理が遅いとか
3万件のリストをORマッパーが処理するのが遅いとか
色々考えられます。

あとはどのような基準で遅いと感じるのでしょうか。
現在具体的に何分かかっていて、
何分以内に処理する必要があるのでしょうか。

投稿2017/08/21 13:19

szk.

総合スコア1400

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問