私の実稼働環境でのMySQLクエリは、私が予想するよりもはるかに時間がかかっています。問題のサイトはかなり大きなDrupalサイトで、多くのモジュールがインストールされています。Webサーバー(Nginx)とデータベースサーバー(mysql)は別々のマシンでホストされ、100 mbpsのLAN接続で接続されています(ホストされています)。 Rackspaceによる)。
開発用にラップトップでまったく同じサイトを実行しています。明らかに、私のラップトップでは、Webサーバーとデータベースサーバーは同じボックスにあります。
これが私のデータベースクエリ時間の結果です:
生産:
320.33ミリ秒で291のクエリを実行しました。 (ホームページ)
999.81ミリ秒で517クエリを実行しました。 (コンテンツページ)
開発:
46.28ミリ秒で316クエリを実行しました。 (ホームページ)
79.09ミリ秒で586クエリを実行しました。 (コンテンツページ)
これらの結果から明らかなように、MySQLサーバーがWebサーバーと同じデータベースで実行されている私のラップトップでは、MySQLデータベースのクエリにかかる時間がはるかに短くなっています。
どうしてこれなの?!
1つの要因は、ネットワークの遅延である必要があります。平均して、Webサーバーからデータベースサーバーへの往復には0.16ミリ秒かかります(pingで表示)。これは、すべての単一のMySQLクエリに追加する必要があります。したがって、上記のコンテンツページの例では、517個のクエリが実行されています。ネットワーク遅延だけで、合計クエリ時間に82ミリ秒が追加されます。しかし、それは私が見ている違いを説明していません(私のラップトップで79ms対プロダクションボックスで999ms)。
他にどのような要素を検討する必要がありますか? NICをギガビット接続にアップグレードすることを考えていましたが、明らかに他の何かが関係しています。
http://www.day32.com/MySQL/ からMySQLパフォーマンスチューニングスクリプトを実行しましたが、データベースサーバーが適切に構成されていることがわかります(明らかにラップトップよりも優れています)。報告された唯一の問題は、「4394の一時テーブルのうち、48%がディスク上に作成された」です。これは両方の環境に当てはまり、本番環境でもmax_heap_table_sizeとCurrent tmp_table_sizeを変更せずに1GBに増やしてみました(これは、BLOB列とTEXT列がいくつかあるためだと思います)。
これは、DBがフロントエンドと同じサーバー上にない場合、クエリごとにラウンドトリップを実行する必要があるためです(回答のサイズによってはさらに多くなる可能性があります)。同じデータセンター内の別のサーバーにpingを実行するのに最大1ミリ秒かかる場合があります。 2つのサーバーが同じラック上にある場合ははるかに少なくなりますが、経験則として1ミリ秒が適切です。
つまり、約300の小さなクエリの場合、表示されているものにかなり近い約300ミリ秒を期待する必要があります。
2つのサーバーが同じマシン上にある場合は、プロセス間でいくつかのコンテキストスイッチを実行するだけで、データをDBプロセスからフロントエンドに移動できます。通常、コンテキストスイッチ(すべての一般的なフラッシュを含む)は約40us(非常に大まかに言えば)かかり、少なくとも2つ必要です(フロントエンドはデータを要求し、DBは要求を読み取り、データを準備して提供し、フロントエンドはデータを読み取りますデータ)。したがって、クエリごとに約80usが必要です(計算を簡単にするために、0.1msに丸めましょう)。したがって、300の小さなクエリで最大30ミリ秒を期待できます。これも、表示されているものにかなり近いものです。
あなたに明確な答えを与えるのは本当に難しいです。サーバーに非常に重いトラフィックがない限り、ネットワークがボトルネックになるとは思いません。
開発マシンと本番サーバーの両方でまったく同じ構成がありますか?
すべてのインデックスが本番サーバーで正常に作成されたことを確認しますか?
それはあなたの本番サーバーのデータ量かもしれません。実稼働マシンと開発マシンの結果を比較するということは、テーブルに同じ数の行があるはずですが、これは本当ですか?
同じインストールファイルを使用して、開発マシンと本番サーバーでMySQLをセットアップしましたか?つまり、開発マシンと本番マシンの両方に同じバージョンのMySQLがありますか?同じOS用ですか?また、32ビットまたは64ビット?おそらく、サーバーにインストールされているMySQLのバージョンのバグです。
可能性は無限大です。詳細がなければ、有益な答えを出すのは非常に困難です。
TCP接続のセットアップと破棄は、ローカルホストで作業する場合、ソケット接続よりもはるかにコストがかかります。ページの読み込みで開始されるデータベースへの接続の数を確認してください。
クエリキャッシュを有効にしていますか?次の出力を見てください。
SHOW VARIABLES LIKE 'query_cache_size';
ゼロより大きい場合はオンになっています。これは、MySQLがサポートするWebサイトのパフォーマンスに大きな違いをもたらしますが、ここでの特定の問題と関係があるかどうかはわかりません。
クエリのセットをキャプチャしてMySQLデータベースサーバーのログインから実行し、そこで状況が異なるかどうかを確認する方法はないと思いますか?
もう1つの考えられる問題は、セッションキャッシュを実行していない場合、データベース呼び出しを行うたびに新しいセッションを開いていることです。セッションキャッシングをしているのか知っていますか?通話ごとに新しいセッションを開くと、ネットワーク全体でコストがかかる可能性があります。
報告された唯一の問題は、「4394の一時テーブルのうち、48%がディスク上に作成された」です。これは両方の環境に当てはまり、本番環境でもmax_heap_table_sizeとCurrent tmp_table_sizeを変更せずに1GBに増やしてみました(これは、BLOB列とTEXT列がいくつかあるためだと思います)。
MySQLのtmpdirをRAMベースのfilesys(tmpfsなど)に配置して、パフォーマンスを向上させることができます。
乾杯
P.S.
パフォーマンスへの影響は、本番環境でのRAID書き込みかもしれません。
ボトルネックがどこにあるかを特定するために私が行うこと:クエリのプロファイリングを行う:http://dev.mysql.com/doc/refman/5.0/en/show-profiles.html
数値がWebサーバーで実行した同じクエリから確認できる数値よりもはるかに少ない場合は、「トランスポート」の問題です。 (ラックスペースネットワークの遅延、スイッチ構成、TEXT
/BLOB
フィールドが返される大量のデータセット(SELECT *)など)
数値がほぼ同じである場合は、クエリを最適化し、構成ファイルを改善する必要があります。これが役立つかもしれないリンクです: https://stackoverflow.com/questions/1191067/how-to-test-mysql-query-speed-with-less-inconsistencies/1191506#1191506
ところで、私のサーバーが100Mbsから1Gbに変わったとき、パフォーマンスの向上は驚くべきものでした!