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コードと静的ファイルはrefreshをクリックするよりも鮮明に提供されます。私はこの小さなスクリプトを実行してPHPをテストしました。

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

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

5000個の sha1 計算を実行しても、ウィンドウが更新されるよりページが鮮明に表示されます。

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

問題はPHPとMySQLの接続にあるはずです - それは私が推論することができた限りです。私は、PHPが遅いことやMySQLが遅いことに関するたくさんのことを見つけることができますが、PHP + MySQLが非常に遅いということは何もありません。

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


私はwin32のためにXAMPP 1.8.0を使っていますinstaller.exe "rel =" nofollow noreferrer ">ダウンロードリンク)
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);

出力:

Connect time: 1.006148
Query time: 0.000247

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

18
@thinice: pastebin.com/4dXe7ZDa
追加された 著者 keen,
php -m出力してください
追加された 著者 thinice,

6 答え

これは私の答えこちらからほぼ逐語的にとられていますが、私たちは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リゾルバに組み込まれています。 。これはIPv6ルックアップが成功することを意味します - しかしMySQLはそのIPv6アドレスに束縛されないので、接続は失敗します、そしてあなたはこの質問で概説された遅れを見るでしょう。

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

いくつかの選択肢があります。インターネットを見てみると、一般的な「解決策」は名前の代わりにIPアドレスを明示的に使用することのようですが、これを行わない理由はいくつかあります。

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

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

それらはかなり重要に思えますか?

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

要約すると、IPアドレスを使用することは最善の解決策ではありませんが、おそらくそれは許容できるものです。

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

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

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

  • The one you are probably familiar with, and the one that you are most likely (effectively) using, 0.0.0.0. This binds to all available IPv4 addresses on the machine. This actually is probably not the best thing to do even if you don't care about IPv6, as it suffers the same security risks as ::.

  • An explicit IPv4 or IPv6 address (for example 127.0.0.1 or ::1 for loopback). This binds the server to that address and only that address.

  • The magic string ::. This will bind MySQL to every address on the machine, both loopback and physical interface addresses, in IPv4 and IPv6 mode. This is potentially a security risk, only do this if you need MySQL to accept connections from remote hosts.

  • Use an IPv4-mapped IPv6 address. This is a special mechanism built into IPv6 for backwards compatibility during the 4 -> 6 transition, and it allows you bind to a specific IPv4 address and it's IPv6 equivalent. This is quite unlikely to be useful to you for anything other than the "dual loopback" address ::ffff:127.0.0.1. This is most likely the best solution for most people, only binding to the loopback but allowing both IPv4 and IPv6 connections.

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

NO. Don't modify the hosts file. The DNS resolver knows what to do with localhost, redefining it will at best have no effect, and at worst confuse the hell out of the resolver.

<�コード>についてはどうすればよいですか。 --skip-name-resolve

これは、関連しているがわずかに異なる理由で、問題を解決することもあります。

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

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

あなたがこれをやろうとしているなら、あなたは名前の代わりにIPアドレスを使うためにあなたのすべての助成金を設定する必要があるでしょう。

30
追加された
bind-addressを :: 1 に変更するまで、localhost上のMySQLへの接続に1秒の遅れがありました。残念ながら、 :: ffff:127.0.0.1 が1秒間の遅延を続けていました( skip-name-resolve を使用しているかどうかにかかわらず)。 (Windows 8.1の場合)
追加された 著者 Simon East,
最後に!ありがとうありがとう!ついに私はすべての原因、可能な解決策およびそれらの対徴候の適切で、完全でそして明確な説明を見つけました。あなたはそれについての本を書くべきです!
追加された 著者 TechnicalTophat,
私はこのまったく同じ問題を抱えていて、何が問題なのかを見つけるまで、コードのランダムなブロックを削除してmysqlサービスを開始し始めるまで、何時間もmysql.iniファイルをいじっていました。それから私はただ 'bind-address MySQL slow loading'とグーグルしてここで見つけました。問題を解決するために bind-address = * を使用しました。詳細を書いてくれてありがとう@DaveRandom!私は WT-NMP 開発用スタックプログラムを使用していましたが、著者がこれを自動車に追加するのを忘れたと思います。 ini設定システム!
追加された 著者 Cosima Maslani,
Windows 7では、 my.inibind-address = :: ffff:127.0.0.1 が機能しません。 127.0.0.1 localhostc:\ Windows \ System32 \ drivers \ etc \ hosts ファイルに明示的に追加するとうまくいきます(1秒の遅延がなくなりました)。
追加された 著者 timodwhit,
@Simon見てもわからないが、デバッグするための最初のステップは、明示的なアドレスを使用してIPv6ループバックとIPv4ループバックの両方に直接接続し、MySQLが実際に両方のスタックで待機し接続可能であることを確認することです。 。
追加された 著者 visyoual,
@RaheelHasan sqlyogを:: 1に向けてみましたか;-)
追加された 著者 visyoual,
そう、:: ffff:127.0.0.1は動作しません...
追加された 著者 Raheel Hasan,
:: 1でバインドした場合、Sqlyogは動作しません...どうすればいいですか?
追加された 著者 Raheel Hasan,
あなたはMySQLのホストアドレスフィールドからからの意味ですか?いいえ、localhostから:: 1に変更しても動作しません
追加された 著者 Raheel Hasan,

接続するたびに、MySQLがrev-dnsクエリを実行しようとしている可能性がありますか。 my.cnf、セクションmysqldに追加してみてください。名前の解決をスキップします。

16
追加された
mysqlを管理するための 'fatアプリケーション' - mysqlワークベンチのように - は遅いですか?
追加された 著者 Steven Arntson,
phpにタイミングを追加して、接続時間が長いか、クエリの実行に時間がかかるかどうかを確認します。
追加された 著者 Steven Arntson,
それからそれは問題だったまっすぐなDNSでした
追加された 著者 Steven Arntson,
あなたは命の恩人です!
追加された 著者 jwp,
それでは、タイミングの結果について頭を悩ませてください。もう一度回答を更新しました。それが完了するのに本当に時間がかかるconnect関数です - 問い合わせは速いです
追加された 著者 keen,
私の問題の解決法が突然笑って明白になり、人々がそれを投票して返事をするのを邪魔しないようになったのでしょうか。
追加された 著者 keen,
skip_name_resolve を使用することはできませんでしたが、 hosts ファイルに 127.0.0.1 localhost を追加することはできました。確かに罪人でした。ありがとう
追加された 著者 keen,
そのコメントをありがとう、私は私の質問を更新しました。接続とクエリの両方が超高速です
追加された 著者 keen,
PHPMyAdminとMySQL CLIクライアントの両方で、奇妙なことに "Host '127.0.0.1'はこのMySQLサーバーに接続できません"と表示されます。何らかの理由でPHPスクリプトはまだ動作しますが、以前と同じくらい遅くなります。
追加された 著者 keen,
MySQL Workbenchから同じクエリを実行するのはCLIクライアントと同じくらい速く、HeidiSQLも同じです。
追加された 著者 keen,
MySQLバージョン5.6.14、これはまだ問題です。 "skip-name-resolve"で解決しました、ありがとう。
追加された 著者 user122261,

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

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

12
追加された
+1これは私にとって正解でした。私はWindows 8で彼らが@DaveRandomがリンクした理由のためにDNSリゾルバに localhost の解決を移したと思います:
追加された 著者 Cristian Adam,
それは私のために働いた:D
追加された 著者 Jared,
これは localhost 以外のサーバーでも起こり得ます。 xx.xxxx.xxxxx.xxxxx.com という形式のサーバーアドレスについても同じ遅延の問題があります。サーバ名をIPアドレスに変更すると、問題は解決しました。
追加された 著者 e9t,

あなたのhostsファイルにこの行を追加することは私のための問題を解決しました

127.0.0.1 localhost

Detailed answer can be found in this thread: https://stackoverflow.com/questions/13584360/php-with-mysql-is-slow

1
追加された
mysql_connect("localhost", "root", "");

その理由が何であるかは明らかです。 PHPはいくつかの点で本当に得意ですが、 'localhost'を '127.0.0.1'に直接変換することは得意ではありません。 あなたはそれを試みなければなりません、それはあなたの全体的なウェブサイトのページロード時間を本当に減らすでしょう、なぜならそれはあなたのHOSTSファイルをチェックすることからPHPを阻止し、

1
追加された
'17からのメモ - mysql_ *関数は現在は非推奨で、php7では削除されています
追加された 著者 Ivan Mikhailov,
私はあなたが問題を示唆しようとしているのか分からない。
追加された 著者 kasperd,
@kasperd 'localhost'のDNS解決
追加された 著者 twinPrimesAreEz,

また、db接続変数(移植性を考慮してスクリプトとは別のファイルにある)を少し調整することで、クエリの速度低下を防ぐこともできます。ホスト値を「localhost」の代わりに「127.0.0.1」に変更します。これはlocalhostのための長いDNSルックアップをバイパスします。

お役に立てれば!

0
追加された
PHP - 日本のコミュニティ [ja]
PHP - 日本のコミュニティ [ja]
4 参加者の

このグループではPHPについて話します。 パートナー:kotaeta.com