从PHP连接到MySQL非常慢


19

我刚刚重新安装了XAMPP。第一次打开PHPMyAdmin时,我注意到它非常慢。在本地主机上打开每个页面大约需要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客户端,用户选择查询甚至不需要花费可观的时间-在我什至没有放下返回键之前就完成了。

问题一定是PHP与MySQL的连接-据我所知。我可以找到大量有关PHP变慢或MySQL变慢的信息​​,但没有发现PHP + MySQL变慢的事实。

感谢任何可以帮助我解决此问题的人!


我正在将XAMPP 1.8.0用于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工作台立即连接


php -m输出请
Thinice

Answers:


17

可能是您的mysql在您每次连接时都尝试运行rev-dns查询吗?尝试添加到my.cnf的mysqld部分:skip-name-resolve


奇怪的是,PHPMyAdmin和MySQL CLI客户端现在都给我“不允许主机'127.0.0.1'连接到该MySQL服务器”。出于某种原因,PHP脚本仍然可以运行,但是和以前一样慢
Hubro 2012年

用于管理mysql的“胖应用程序”(如mysql workbench)是否很慢?
pQd 2012年

从运行MySQL工作台相同的查询是一样快的CLI客户端,所以是HeidiSQL
Hubro

在php中添加一些计时,并检查它是否连接或运行需要很多时间的查询。
pQd 2012年

感谢您的评论,我更新了我的问题。连接和查询都非常快
Hubro 2012年

30

这几乎是从我在这里的答案中得到的,但我知道我们对SO上仅链接的答案不满意,所以我想你们也是如此:-)

如果您遇到此问题并使用Windows 7之前的Windows版本,则可能无法解决问题。

为什么会这样呢?

此问题的原因是IPv4与IPv6。

当您使用主机名而不是IP地址时,MySQL客户端首先运行AAAA该名称的(IPv6)主机查找,如果成功将名称解析为IPv6地址,则首先尝试使用该地址。如果任一步骤失败(名称解析或连接),它将回退到IPv4,运行A查找并尝试使用此主机。

实际上,这意味着如果IPv6 localhost查找成功但MySQL未绑定到IPv6回送,则您将需要等待一个连接超时周期,然后才发生IPv4回退并且连接成功。

在Windows 7之前,这不是问题,因为localhost解析是通过hosts文件完成的,并且仅预先配置了127.0.0.1-它没有与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或更高版本,并且需要使用--bind-address=命令行参数启动MySQL 。您有4个选项docs,具体取决于您要执行的操作:

  • 您可能熟悉的一种,最有可能(有效地)使用的一种0.0.0.0。这将绑定到计算机上所有可用的IPv4地址。即使您不关心IPv6,这实际上也不是最好的做法,因为它遭受与相同的安全风险::

  • 明确的IPv4或IPv6地址(例如127.0.0.1::1用于回送)。这会将服务器绑定到该地址,并且绑定到该地址。

  • 魔术弦::。这将以IPv4和IPv6模式将MySQL绑定到计算机上的每个地址,包括回送和物理接口地址。这可能存在安全风险,仅当您需要MySQL接受来自远程主机的连接时,才这样做。

  • 使用IPv4映射的IPv6地址。这是IPv6内置的一种特殊机制,用于在4-> 6过渡期间向后兼容,它允许您绑定到特定的IPv4地址及其等效的IPv6。除了“双重回送”地址之外,这对于您几乎没有用::ffff:127.0.0.1。对于大多数人来说,这很可能是最好的解决方案,它仅绑定到环回,但同时允许IPv4和IPv6连接。

我需要修改主机文件吗?

NO。不要修改主机文件。DNS解析器知道如何处理localhost,重新定义它最多没有效果,最坏的情况是使解析器混乱。

--skip-name-resolve

由于相关但略有不同的原因,这也可以解决问题。

如果没有此配置选项,MySQL将尝试通过PTRDNS查询将所有客户端连接IP地址解析为主机名。如果您的MySQL服务器已经启用了使用IPv6的功能,但连接仍需要很长时间,则可能是因为反向DNS(PTR)记录配置不正确。

禁用名称解析将解决此问题,但是它还有其他影响,特别是配置为在这种Host情况下使用DNS名称的任何访问权限现在都将失败。

如果要执行此操作,则需要将所有授权配置为使用IP地址而不是名称。


2
最后!谢谢谢谢!最后,我找到了对所有原因,可能的解决方案及其禁忌症的正确,完整和清晰的解释。您应该写一本书!
tobia.zanarella 2014年

4
在将bind-address更改为之前,我在本地主机上连接MySQL的延迟为1秒::1。不幸的是::ffff:127.0.0.1继续给了我1秒钟的延迟(无论是否使用skip-name-resolve),有什么想法吗?(在Windows 8.1上)
Simon East

1
@Simon这是一个线索,但调试的第一步是尝试使用显式地址直接连接到IPv6环回和IPv4环回,以验证MySQL实际上在两个堆栈上均处于侦听和可连接状态,并从此处进行调试。
DaveRandom 2014年

1
是的,:: ffff:127.0.0.1无效...
Raheel Hasan 2014年

如果我将它与:: 1绑定,则Sqlyog无法正常工作...该怎么办?
Raheel Hasan 2014年

13

通常,在服务器中启用IPv6时,使用MySQL的连接localhost速度非常慢。

更改脚本中的mysql服务器地址即可127.0.0.1解决该问题。


+1这对我来说是正确的答案。我想在Windows 8中,他们搬到分辨率localhost的DNS解析的原因,@DaveRandom链接:serverfault.com/questions/4689/...
wwarren

它对我
有用

除以外的其他服务器也可能发生这种情况localhost。表单上的服务器地址存在相同的延迟问题xx.xxxx.xxxxx.xxxxx.com。一旦将服务器名称更改为其IP地址,问题就消失了。
Gruber 2014年

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

好吧,原因很明显。PHP确实擅长某些方面,但不能直接将“ localhost”转换为“ 127.0.0.1”。您必须尝试这样做,因为它可以阻止PHP检查您的HOSTS文件,并且不采取任何措施来获取'localhost'后面的真实IP地址,这实际上会减少网站的总体加载时间。


我无法弄清楚您要暗示的问题是什么。
kasperd 2014年

@kasperd DNS解析“ localhost”
Xesau 2014年

'17的注释-现在不推荐使用mysql_ *函数,并在php7
中将其


0

您还可以通过对db连接变量进行少量调整来消除查询速度降低的情况(希望该变量与脚本在单独的文件中,以实现可移植性)。将主机值更改为“ 127.0.0.1”,而不是“ localhost”。这绕过了冗长的本地主机DNS查找。

希望这可以帮助!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.