web-dev-qa-db-ja.com

PHPからMySQLへの接続が非常に遅い

XAMPPの新規インストールを実行しました。 PHPMyAdminを最初に開いたとき、非常に遅いことに気付きました。 localhostでは、すべてのページが開くまでに約5秒かかることは意味がありませんでした。 PHPMyAdminを非難する小さなテストケースを作成しました。

$con = new PDO("mysql:Host=localhost;dbname=mysql", "root", "");
$statement = $con->query('SELECT Host,user,password FROM user;');
$users = $statement->fetchAll(PDO::FETCH_ASSOC);

上記のスクリプトの実行には約3秒かかります(最初に実行したときのロードには8秒近くかかりましたが)。

次に、PDOのせいかどうかを確認するために、mysql_connect代わりに:

$con = mysql_connect("localhost", "root", "");
mysql_select_db("mysql", $con);
$result = mysql_query('SELECT Host,user,password FROM user;');

終了するまで正確に時間がかかります。

最初はPHPのせいだと思っていましたが、PHPコードと静的ファイルは、更新をクリックするよりも速く提供されます。テストしたPHPこの小さなスクリプトを実行して:

header("Content-Type: text/plain");

for($i = 0; $i < 5000; $i++)
{
    echo sha1(Rand()) . "\n";
}

5000 sha1計算と、ページを更新しても、ウィンドウを更新できない場合があります。

それから、MySQLのせいだと思った。しかし、繰り返しになりますが、MySQLが必要以上に高速に動作していることを確認するために、あまりテストを行いませんでした。 MySQL CLIクライアントを使用すると、ユーザー選択クエリに測定可能な時間さえかかりません。それは、Returnキーを離す前に行われます。

問題は、MySQLへのPHPの接続である必要があります。これは、私が推論できる限りです。 PHPが遅い、またはMySQLが遅い)に関するものはたくさんありますが、PHP + MySQLが極端に遅いことについては何も見つかりません。

これを解決するのを手伝ってくれる人に感謝します!


XAMPP 1.8.0 for win32を使用しています( ダウンロードリンク
PHPバージョン:5.4.4
MySQLバージョン:14.14


編集:タイミングの後、それは非常に時間がかかっている接続機能であることがわかります:

$time = microtime(true);

$con = mysql_connect("localhost", "root", "");
mysql_select_db("mysql", $con);

$con_time = microtime(true);

$result = mysql_query('SELECT Host,user,password FROM user;');

$sel_time = microtime(true);

printf("Connect time: %f\nQuery time: %f\n",
       $con_time-$time,
       $sel_time-$con_time);

出力:

接続時間:1.006148 
クエリ時間:0.000247

PHPがデータベースへの接続に多くの時間を費やす原因となるものは何ですか?CLIクライアント、HeidiSQL、MySQLワークベンチは即座に接続します

20
Hubro

あなたのmysqlが接続するたびにrev-dnsクエリを実行しようとする可能性がありますか? my.cnfのセクションmysqldに追加してみてください: skip-name-resolve

17
pQd

これは私の答えからほとんど逐語的に取られます ここ ですが、SOのリンクのみの答えは私たちが眉をひそめているので、皆さんもそうだと思います:-)

この問題があり、Windows 7より前のバージョンのWindowsを使用している場合、これはおそらく問題の答えにはなりません。

なぜこれが起こっているのですか?

この問題の原因は、IPv4対IPv6です。

IPアドレスの代わりにホスト名を使用すると、MySQLクライアントは最初にAAAA(IPv6)ホストルックアップを実行し、名前がIPv6アドレスに正常に解決されると、最初にこのアドレスを試します。いずれかのステップ(名前解決または接続)が失敗すると、IPv4にフォールバックし、Aルックアップを実行して、代わりにこのホストを試行します。

これが実際に意味することは、IPv6 localhostルックアップは成功したが、MySQLがIPv6ループバックにバインドされていない場合、IPv4フォールバックが発生して接続が成功するまで、1つの接続タイムアウトサイクルを待つ必要があります。

localhostの解決はhostsファイルを介して行われ、127.0.0.1のみで事前構成されていたため、これはWindows 7より前の問題ではありませんでした-IPv6の対応物::1は付属していません。

ただし、Windows 7以降では、localhost解決がDNSリゾルバーに組み込まれています。これは、概説されている理由により here です。これは、IPv6ルックアップが成功することを意味しますが、MySQLはそのIPv6アドレスにバインドされていないため、接続は失敗し、この質問で説明されている遅延が表示されます。

いいですね。修正方法を教えてください!

いくつかのオプションがあります。インターネットを見回すと、一般的な「解決策」は名前ではなくIPアドレスを明示的に使用することですが、これを行わない理由はいくつかあります。どちらも移植性に関連しており、どちらもおそらく重要ではありません。

  • onlyがIPv6をサポートする別のマシンにスクリプトを移動すると、スクリプトは機能しなくなります。

  • スクリプトを* nixベースのホスティング環境に移動した場合、マジックストリングlocalhostは、MySQLクライアントが構成されている場合、Unixソケットを使用することを好むことを意味します。これは、IPループバックベースの接続よりも効率的です。

しかし、彼らはかなり重要に聞こえますか?

そうではありません。この種のことが構成ファイルで定義されるように、アプリケーションを設計する必要があります。スクリプトを別の環境に移動する場合は、他にも構成が必要になる可能性があります。

要約すると、IPアドレスの使用はbestソリューションではありませんが、許容できるソリューションである可能性が高いです。

それで、最善の解決策は何ですか?

最善の方法は、MySQLサーバーが使用するバインドアドレスを変更することです。ただし、これは簡単なことではありません。 Apache、Nginx、およびこれまでに作成されたほぼすべての正常なネットワークサービスアプリケーションとは異なり、MySQLは単一のバインドアドレスしかサポートしないため、別のアドレスを追加するだけではありません。幸いにも、ここではオペレーティングシステムがちょっとした魔法をサポートしているので、MySQLでIPv4とIPv6の両方を同時に使用できます。

MySQL 5.5.3以降を実行している必要があり、--bind-address=コマンドライン引数を使用してMySQLを起動する必要があります。 4つのオプションがありますドキュメント、何をしたいかに応じて:

  • おそらくあなたがよく知っているものであり、最も効果的に(効果的に)使用しているもの、0.0.0.0。これは、マシンで使用可能なすべてのIPv4アドレスにバインドします。 ::と同じセキュリティリスクがあるため、IPv6を気にしない場合でも、これは実際にはおそらく最善の方法ではありません。

  • 明示的なIPv4またはIPv6アドレス(たとえば、ループバックの場合は127.0.0.1または::1)。これにより、サーバーがそのアドレスとonlyにバインドされます。

  • マジックストリング::。これにより、IPv4およびIPv6モードで、MySQLがループバックアドレスと物理インターフェイスアドレスの両方のマシン上のすべてのアドレスにバインドされます。これは潜在的にセキュリティリスクです。これは、MySQLがリモートホストからの接続を受け入れる必要がある場合にのみ行ってください。

  • IPv4-mapped IPv6アドレス を使用します。これは、4から6への移行中に下位互換性を保つためにIPv6に組み込まれた特別なメカニズムであり、特定のIPv4アドレスと同等のIPv6アドレスにバインドできます。これは、「デュアルループバック」アドレス::ffff:127.0.0.1以外では役に立ちません。これはほとんどの場合、ループバックにバインドするだけでIPv4とIPv6の両方の接続を許可する最善のソリューションです。

hostsファイルを変更する必要がありますか?

[〜#〜]いいえ[〜#〜]。 hostsファイルは変更しないでください。 DNSリゾルバーはlocalhostの処理方法を認識しているため、再定義しても効果はなく、最悪の場合、リゾルバーの地獄を混乱させることになります。

--skip-name-resolve についてはどうですか?

これにより、関連するが少し異なる理由で問題が解決する場合もあります。

この構成オプションがない場合、MySQLはPTR DNSクエリを介してすべてのクライアント接続IPアドレスをホスト名に解決しようとします。 MySQLサーバーでIPv6の使用がすでに有効になっているのに接続にまだ時間がかかる場合は、逆引きDNS(PTR)レコードが正しく構成されていない可能性があります。

名前解決を無効にするとこの問題は解決しますが、特にHost条件でDNS名を使用するように構成されたアクセス許可が失敗するという他の影響があります。

これを行う場合は、名前の代わりにIPアドレスを使用するようにすべての許可を構成する必要があります。

30
DaveRandom

通常、サーバーでIPv6が有効になっている場合、localhostを使用したMySQLへの接続は非常に遅くなります。

スクリプトのmysqlサーバーアドレスを127.0.0.1に変更すると、問題が解決します。

13
Doug

この行をhostsファイルに追加すると、問題が解決しました

127.0.0.1 localhost

詳細な回答はこのスレッドにあります: https://stackoverflow.com/questions/13584360/php-with-mysql-is-slow

1
user2537018
mysql_connect("localhost", "root", "");

さて、その理由が何であるかは非常に明白です。 PHP一部の点では非常に優れていますが、「localhost」を「127.0.0.1」に直接変換するのは得意ではありません。それを試す必要があります。 PHP HOSTSファイルのチェックから戻って、「localhost」の背後にある実際のIPアドレスを取得するために何をしていないか

1
Xesau

また、db接続変数に小さな調整を加えることで、クエリのスローダウンをなくすこともできます(移植性を高めるために、スクリプトとは別のファイルにすることをお勧めします)。ホストの値を「localhost」ではなく「12.7.0.1」に変更します。これにより、localhostの長いDNSルックアップがバイパスされます。

お役に立てれば!

0
Billman64