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

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に必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

PHP

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

Q&A

解決済

3回答

3292閲覧

SQLの実行結果を計測する方法

gojira

総合スコア2

MySQL

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

SQL

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

WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

PHP

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

0グッド

0クリップ

投稿2020/05/14 09:59

前提・実現したいこと

MySQL(WordPress)で下記2つの関数にあるSQLどちらがいいのか計測して調べてみようと思いました。
計測はできたのですが、関数をその都度変えたいので、計測する関数 test_rate() の引数に、計測される2つの関数を渡したいです。

発生している問題・エラーメッセージ

test_rate() の引数に、計測される2つの関数を渡す方法がわかりません。(ていうか、できますか?)

該当のソースコード

まず計測される2つの関数は次の通り、test_get_var1() と test_get_var2() です。

PHP

1// 「 $his_id が投稿した thread 」 への comment を取得 (var1) 2function test_get_var1( $his_id ){ 3 global $wpdb; 4 $sql = " 5 SELECT w.thing_id, w.kind_id 6 FROM( 7 SELECT base_t.thing_id 8 ,base_t.kind_id 9 ,parent_t.user_id AS parent_thread_author_id 10 FROM wp_things base_t 11 LEFT JOIN wp_things_comment base_tc 12 ON base_tc.comment_id=base_t.thing_id 13 LEFT JOIN wp_things parent_t 14 ON parent_t.thing_id=base_tc.parent_thread_id AND parent_t.kind_id=2 15 ) AS w 16 WHERE w.kind_id=3 AND w.parent_thread_author_id=$his_id 17 "; 18 $rows = $wpdb->get_results( $sql, ARRAY_A ); 19 return $rows; 20} 21 22// 「 $his_id が投稿した thread 」 への comment を取得 (var2) 23function test_get_var2( $his_id ){ 24 global $wpdb; 25 $sql = " 26 SELECT base_t.thing_id 27 FROM wp_things base_t 28 LEFT JOIN wp_things_comment base_tc 29 ON base_tc.comment_id=base_t.thing_id 30 WHERE base_tc.parent_thread_id IN ( 31 SELECT parent_t.thing_id 32 FROM wp_things parent_t 33 WHERE parent_t.user_id=$his_id AND parent_t.kind_id=2 34 ) 35 "; 36 $rows = $wpdb->get_results( $sql, ARRAY_A ); 37 return $rows; 38} 39

そして計測する関数は次の通り test_rate() で、以下の場合は test_get_var1() しか計測できません。

php

1function test_rate( $lim ){ 2 $arr = []; 3 for ($i = 0; $i < $lim; $i++){ 4 $time_start = microtime(true); 5 $func = test_get_var1(1); 6 $time = microtime(true) - $time_start; 7 $arr[] = $time; 8 } 9 10 // 平均 11 $sum = array_sum($arr); 12 $average = $sum/count($arr); 13 return $average; 14}

このように、上記の test_rate() はその関数内に test_get_var1() があるので test_get_var2() を計測するためにはこの部分を書き換えないといけません。

なので test_rate() の引数に、test_get_var1() や test_get_var2() を渡すことができればいいと考えたのですが、何かそのような方法はありますか?

試したこと

「関数 引数」で調べるとコールバック関数というのを見つけて近いのかなと思い、test_rate() で次のように文字列で関数を渡してみたのですが、実現することができませんでした。

php

1// 計測結果を出力するために、計測される関数を文字列で渡す 2echo json_encode( test_rate( 100, "test_get_var1($his_id)" ) ); 3 4// 計測を実行 5function test_rate( $lim, $func_str ){ 6 $arr = []; 7 for ($i = 0; $i < $lim; $i++){ 8 $time_start = microtime(true); 9 func_go($func_str); 10 $time = microtime(true) - $time_start; 11 $arr[] = $time; 12 } 13 14 // 平均 15 $sum = array_sum($arr); 16 $average = $sum/count($arr); 17 return $average; 18} 19 20// 文字列で渡した関数を実行 21function func_go($func_str){ 22 return $func_str(); 23} 24

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

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

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

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

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

guest

回答3

0

ベストアンサー

アプリケーション側で実行しても画面出力やSQL本来とは関係のないロジックにより純粋な結果にはなりません。
実行予定のSQLを取得し、それぞれ実行計画をとってください。

別解

ちなみに、コマンドで実行するとちゃんと実行時間が返ってきます。
イメージ説明
※EXPLAINでもなくてもOK

なので、「アプリケーションから実行しないこと」って言ってたんですけどね。

投稿2020/05/14 12:01

編集2020/05/15 10:48
m.ts10806

総合スコア80850

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

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

gojira

2020/05/15 07:13

>アプリケーション側で実行しても画面出力やSQL本来とは関係のないロジックにより純粋な結果にはなりません。 というのはPHPの処理のことですか?つまりforやmicrotime()の処理がかかってしまい、純粋なSQLの処理が測れないという意味ですか?
gojira

2020/05/15 07:13

>実行予定のSQLを取得し、それぞれ実行計画をとってください。 リンク先のexplainですが、それによってかかった時間を見ることはできるのでしょうか?以下しか見れないように思いました。 select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、filtered、Extra これらの中から、またはほかの項目から、仮に時間が測れるとしたらどのようにでしょうか?
m.ts10806

2020/05/15 07:15

まず実行してみては。
gojira

2020/05/15 07:39

すみません何をでしょうか?explain以外に特に心当たりがなく苦慮しています。
m.ts10806

2020/05/15 07:41

>以下しか見れないように思いました。 これだと「ドキュメントを読んだ感想」だと捉えます。
gojira

2020/05/15 08:23

いえ実行したうえのことです。「できませんでした」ではあなたのアドバイスに対して角がたつので「できないように思います」と柔らかく書いたのですが…女性的すぎて伝わらなかったですね、すみません。 まぁどのように捉えてしまったかはいいとして、いずれによ、explainでは時間は取得できませんでした。
gojira

2020/05/15 08:50 編集

ちなみにexplainはこうなります。ここから時間を取得できる見方やテクニックがあれば教えて頂きたいです。 array(3) { [0]=> array(10) { ["id"]=> string(1) "1" ["select_type"]=> string(6) "SIMPLE" ["table"]=> string(8) "parent_t" ["type"]=> string(11) "index_merge" ["possible_keys"]=> string(41) "PRIMARY,idx_wp_things_01,idx_wp_things_02" ["key"]=> string(33) "idx_wp_things_01,idx_wp_things_02" ["key_len"]=> string(3) "8,4" ["ref"]=> NULL ["rows"]=> string(1) "3" ["Extra"]=> string(76) "Using intersect(idx_wp_things_01,idx_wp_things_02); Using where; Using index" } [1]=> array(10) { ["id"]=> string(1) "1" ["select_type"]=> string(6) "SIMPLE" ["table"]=> string(7) "base_tc" ["type"]=> string(3) "ref" ["possible_keys"]=> string(24) "PRIMARY,parent_thread_id" ["key"]=> string(16) "parent_thread_id" ["key_len"]=> string(1) "8" ["ref"]=> string(28) "zjp_g56ui4.parent_t.thing_id" ["rows"]=> string(1) "1" ["Extra"]=> string(11) "Using index" } [2]=> array(10) { ["id"]=> string(1) "1" ["select_type"]=> string(6) "SIMPLE" ["table"]=> string(6) "base_t" ["type"]=> string(6) "eq_ref" ["possible_keys"]=> string(24) "PRIMARY,idx_wp_things_02" ["key"]=> string(7) "PRIMARY" ["key_len"]=> string(1) "8" ["ref"]=> string(29) "zjp_g56ui4.base_tc.comment_id" ["rows"]=> string(1) "1" ["Extra"]=> string(11) "Using where" } }
m.ts10806

2020/05/15 08:34

はい。事実だけ端的に言ってもらえば良いです。できないならできないで、次の策を考えるだけで、「できないはずないだろう何やってんだ」と噛みつくつもりは毛頭ないです。 変に包むと解釈同士ぶつかってすれ違いしか起きません。 プログラムは書いた通りにしか動きませんが、それと同じく、コメントも書いた通りにしか伝わりません。 ちなみに「何をどう実行して」の結果なのかがわかりません。コードならコードを提示してください。
gojira

2020/05/15 08:44

コードはこちらで、EXPLAIN を追加しただけです。 var_dump( test_get_var1( $his_id ) ); function test_get_var1( $his_id ){ global $wpdb; $sql = " EXPLAIN # ←追加 SELECT w.thing_id, w.kind_id /*以下同じ*/ }
gojira

2020/05/15 09:01

やはりexplainで時間は確認できないのでは…
m.ts10806

2020/05/15 09:05

出力内容以前に、「アプリケーション側から実行しないこと」というのを忘れてませんか。 DBに対して直に実行してください。PHPを介してはいけません。
gojira

2020/05/15 11:04

すみません今気づきました。ご回答への画像記載誠にありがとうございます。 たしかに時間の表示ができていますね! ただ「コマンドで実行」や「DBに対して直に実行」というのがいまいち理解できないでおります。 恐らくWordPressでいうとphpMyAdminの画面の「SQLタブ」内にSELECT文を入力するということかと思いそれを実行したところ、以下が表示されました。 行 0 - 4 の表示 (合計 5, Query took 0.0005 seconds.) たしかに0.0005と時間の表示ができていますね! この理解であっていますでしょうか。 もしこの理解であっているとしますと、先の「SQLタブ」内には質問のようなfor文は書けませんよね。するとここでtest_get_var1とtest_get_var2のSELECT文を複数実行してその平均速度を比較するような方法があるのかと思いますが、どういったものになりますか? SELECT自体をループさせるとかいう方法があれば最適なのですが… 調べますと https://teratail.com/questions/159033 があったものの「SQLにはLOOPはサポートされていません」というご回答があり難航しています。 イメージとしてはこのようになるでしょうか。 WHILE 0 < 10 質問にあるSELECT文をここに書く END
m.ts10806

2020/05/15 11:13

> 恐らくWordPressでいうとphpMyAdminの画面 phpMyAdminもMySQLを操作するために作られたツールに過ぎないので、「WordPressで言うところの」という前提は不要かと思います。 MySQLに対して直にアプローチできる方法であれば良いのです。 PHPを介すと結局は「PHPで使うための情報」に変換されるため、直にアプローチが必要であると説いています。 特にWordPressのようなCMSであれば尚更でしょうね(PHP自体は得意だけど、WordPressの中身の仕組みは詳しくない) >この理解であっていますでしょうか。 はい。合っています。phpMyAdminもPHPで作られたツールですが、うまいこと「生の実行結果に近い出力」がされるように工夫されているのでしょう。 > SELECT文を複数実行してその平均速度を比較するような方法があるのかと思いますが、どういったものになりますか? コマンドであれば「実行結果をテキストに出力する」といったこともできます。 なので、Windowsであればbatのようなスクリプトを組み、ループさせて生の実行結果を出力して、そこから拾うような形になるのではないでしょうか。 「PHPから実行する」のはいったん離れてください。 MySQLはPHPからすると外部の仕組みです。「純粋な実行時間」を計測したいのであれば直に実行するしかありません。
gojira

2020/05/15 11:34

一つずつご丁寧に大変ありがとうございます。 「batのようなスクリプトを組み、ループさせて生の実行結果を出力して、そこから拾う」というのがかなり難解に感じます…。 phpmyAdminのSQLタブ内に入力するコードとして、「コレとアレにSELECT文を挟めば、そのSELECT文が10回実行される」といった方法はございませんでしょうか。このようにです。 コレ(10回) SELECT文 アレ 調べてもストアドプロシージャとかやたらと複雑なものばかりで、上記のようなシンプルな書き方があってもよさそうに思ったのですが。
m.ts10806

2020/05/15 12:08

DBに直接関係することはインフラ要素が強いです。 全く知見がないのでしたら難解で当然です。 「環境構築」と聞いて「難しそうだな」と思うのでしたらそういうレベルのことをやろうとしているという認識でいてください。 もちろん知見が多少でもあれば考え付くことなので、あとは「どうなりたいか」で決めてください。 先に書いたようにphpMyAdminも単なるツールです。直接DBに対して操作するほどの柔軟さはありません。
gojira

2020/05/15 12:18

なるほど簡単な方法があればと思いましたが、少し手が届かなそうですね。それがわかっただけで十分です。どうも長々とお付き合いくださいましてありがとうございました。
m.ts10806

2020/05/15 12:22

はい。あとはどうなりたいかで決めてください。 「サーバー側の検証」なので結構大変です。私も思いつく方法を挙げてはみたものの、あくまで「案」で、実証するためには段階を重ねて検証したうえでツールを1本作る必要があると思ってます。
guest

0

WordPressでクエリの処理時間を見るだけならプラグインを入れたほうが早いと思います。

【[WP]WordPressが重い時は「Query Monitor」でクエリ実行時間などをモニターしよう | WEBデザインのTIPSまとめサイト「ウェブアンテナ」】
https://www.webantena.net/wordpress/plugin-query-monitor/

【Query Monitor – The Developer Tools Panel for WordPress】
https://querymonitor.com/

投稿2020/05/15 08:50

kei344

総合スコア69400

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

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

gojira

2020/05/15 08:54

WordPressにお詳しそうな方で助かります。ご回答ありがとうございます。 Query Monitor ですが、質問のように100回実行してその平均をとったりというのができないのでどうしたものかと困っています。何かいい方法ございますでしょうか。
kei344

2020/05/15 09:03

特に詳しくないです。 100回実行してその値をとって平均すればよいのでは。 そもそもクエリのことだけならDBサーバに直接クエリを投げて計測したほうが早い気がします。
gojira

2020/05/15 09:24

>100回実行してその値をとって平均すればよいのでは。 なるほど、Query Monitor のリストに対して以下の流れでしょうか。 // Query Monitor の時間リストを配列にする var func = 'test_get_var1'; var times = []; $('[data-qm-caller="'+func+'"]').each(function(){ var time = Number( $(this).attr('data-qm-time') ); times.push(time); }); console.log( times ); // 配列の平均を求める let res = times.reduce( ( pre, curr, i )=> { return pre + curr; }, 0 ) / times.length; console.log( res );
gojira

2020/05/15 09:25

>そもそもクエリのことだけならDBサーバに直接クエリを投げて計測したほうが早い気がします。 すみませんこちらどういう意味ですか?DBサーバーに直接クエリを投げるという作業をしたことがなく、また方法が想像できないでおります。
kei344

2020/05/15 09:38

WordPressなどの仕組み上、同じクエリはキャッシュされる可能性があります。 > すみませんこちらどういう意味ですか? クエリの速度を比較するなら、クエリを実行しているのはDBサーバなのだから、直接DBサーバにクエリを投げて計測するとかしたほうが正確で早いと思う、というそのままの意味です。 会社での話であればDBエンジニアやサーバエンジニアに相談すればよいです。個人での場合は、数回実行してみて特に大きな差が出るとか、特別遅くないなら大して比較する意味は無いと思います。
gojira

2020/05/15 09:43 編集

難しそうですし個人の話なので、JSの方法でよさそうですね。ただ同じクエリがキャッシュされるとなると、JSの方法でも弊害があるのでしょうか。例えば数回実行しても最初以外はキャッシュが効いているために早くなってしまうなどですか?そうするとJSの方法でも結局測れてないということでしょうか?
kei344

2020/05/15 09:45

(再掲)WordPressなどの仕組み上、同じクエリはキャッシュされる可能性があります。 (再掲)数回実行してみて ページに表示されたものはWordPressが生成したHTMLです。
gojira

2020/05/15 09:48

すみません理解できないです…。下記はイエスでしょうか?それとも勘違いが多くてイエスともノーとも言えないようなコメントでしょうか? 同じクエリがキャッシュされるとなると、JSの方法でも弊害があるのでしょうか。例えば数回実行しても最初以外はキャッシュが効いているために早くなってしまうなどですか?そうするとJSの方法でも結局測れてないということでしょうか?
gojira

2020/05/15 09:50

JSの方法というのは「2020/05/15 18:24」に載せたJSのことです。Querymonitorで実行し、SQLの実行結果リストが100個でたものに対し、F12でコンソール画面を開き、このJSを実行して平均を求める。という方法です。
kei344

2020/05/15 10:16

少なくともやってから(速度を計測して比較してから)聞きましょう。で、問題があるかどうかは自身で判断しましょう。
gojira

2020/05/15 11:10

同じ処理で同じ実行時間になるならばキャッシュが効いてる場合に実行時間が異なることでわかりますが、SQLの実行時間はその都度異なるので、キャッシュが効いているかいないかわかるほどの差が出ないですね… まぁ…判断しましょうとのことで、あれこれとお手をわずらせてすみません。JSの方法は結局不明なのでやめて、またほかの方法で模索しておきます。
guest

0

インデックスを貼っていてもデータ量によっては使用されない場合もあります
スロークエリーが発生したり、明らかに挙動が遅い場合は
php側で測定して、対策をとればよいでしょう

投稿2020/05/15 03:10

yambejp

総合スコア114777

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

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

gojira

2020/05/15 07:14

仰る通りphp側で測定をするコードが test_rate() で、それを動作させるための解決策を探している、というのが現状でございます。解決策について何かございましたらぜひアドバイス頂戴したく。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問