从PHP连接到MySQL是非常缓慢的

我刚刚安装了XAMPP。 当第一次打开PHPMyAdmin时,我注意到它非常缓慢。 在本地主机上打开每个页面需要将近5秒钟,这是没有意义的。 我做了一个小小的testing案例,将责备推移到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秒的时间才能运行(尽pipe第一次运行时花费了将近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代码和静态文件服务比我可以点击刷新更快。 我通过运行这个小脚本来testingPHP:

 header("Content-Type: text/plain"); for($i = 0; $i < 5000; $i++) { echo sha1(rand()) . "\n"; } 

5000 sha1计算和页面仍然显示比我刷新我的窗口更快捷。

然后我觉得这是MySQL的错。 但是,再次,没有太多的testing,发现MySQL的工作比我需要的更快。 使用MySQL CLI客户端,用户select查询甚至不需要花费可测量的时间,甚至在我还没有让返回键之前完成。

这个问题必须是PHP与MySQL的连接 – 就我所能理解的那样。 我可以find很多关于PHP缓慢或者MySQL慢的东西,但是关于PHP + MySQL的一切都不是很慢。

感谢任何人可以帮助我解决这个问题!


我正在使用XAMPP 1.8.0 for win32( 下载链接 )
PHP版本:5.4.4
MySQL版本:14.14


编辑:计时后,事实certificate这是连接function,这是花了这么久:

 $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工作台立即连接

你可以在你连接的时候尝试运行rev-dns查询吗? 尝试添加到my.cnf,部分mysqld: skip-name-resolve 。

这几乎是从我的答案这里 ,但我知道我们皱眉只有链接的答案,所以我想你们做的一样好:-)

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

为什么发生这种情况?

这个问题的原因是IPv4 vs IPv6。

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

这实际上意味着,如果IPv6 localhost查找成功,但是MySQL没有绑定到IPv6回环,则需要等待一个连接超时周期,然后IPv4回退并且连接成功。

这在Windows 7之前不是问题,因为localhostparsing是通过主机文件完成的,它只是预configuration了127.0.0.1 – 它没有与它的IPv6对应项::1

但是,从Windows 7开始, localhostparsing程序就内置在DNSparsing程序中,原因如下。 这意味着IPv6查找现在将成功 – 但是MySQL不绑定到该IPv6地址,因此连接将失败,您将看到此问题中列出的延迟。

这很好。 只要告诉我如何解决它已经!

你有几个select。 环顾互联网,一般的“解决scheme”似乎是明确地使用IP地址而不是名称,但有几个原因不这样做,无论是可移植性相关,都可以说是不重要的:

  • 如果将脚本移动到支持IPv6的另一台计算机,则脚本将不再工作。

  • 如果你的脚本移动到一个基于nix的托pipe环境中,魔术stringlocalhost将意味着MySQL客户端更喜欢使用一个Unix套接字(如果configuration的话),这比基于IP回送的连接更有效率

他们听起来很重要?

他们不是。 您应该devise您的应用程序,以便这样的事情在configuration文件中定义。 如果你把你的脚本移动到另一个环境,其他的东西也可能需要configuration。

总之,使用IP地址并不是最好的解决scheme,但它很可能是一个可以接受的解决scheme。

那么最好的解决scheme是什么?

最好的方法是更改​​MySQL服务器使用的绑定地址。 但是,这并不像人们想象的那么简单。 与Apache,Nginx以及其他几乎所有的networking服务应用程序不同,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 for loopback)。 这将服务器绑定到该地址, 只有该地址。

  • 魔术string:: 。 这将绑定MySQL到机器上的每个地址,包括环回和物理接口地址,在IPv4和IPv6模式。 这可能是一个安全风险,只有当您需要MySQL接受来自远程主机的连接时才会这样做。

  • 使用IPv4映射的IPv6地址 。 这是一个内置于IPv6中的特殊机制,用于在4→6转换期间向后兼容,并允许您绑定到特定的IPv4地址,并且它与IPv6等效。 对于除“双重回送”地址::ffff:127.0.0.1之外的任何内容,这都不太可能有用。 这对于大多数人来说很可能是最好的解决scheme,只能绑定到回送,但同时允许IPv4和IPv6连接。

我需要修改hosts文件吗?

NO 。 不要修改主机文件。 DNSparsing器知道如何处理localhost ,重新定义它最多不会有任何效果,最坏的情况是把解决方法搞糊涂了。

那么--skip-name-resolve呢?

这也可以解决这个问题,一个相关的,但稍有不同的原因。

如果没有这个configuration选项,MySQL将尝试通过PTR DNS查询将所有客户端连接IP地址parsing为主机名。 如果您的MySQL服务器已经启用了使用IPv6,但连接仍然需要很长时间,可能是因为反向DNS( PTR )logging没有正确configuration。

禁用名称parsing可以解决这个问题,但是确实有其他的后果,特别是configuration为在Host条件下使用DNS名称的任何访问权限现在都会失败。

如果您要这样做,您需要将所有授权configuration为使用IP地址而不是名称。

通常,当在服务器上启用IPv6时,使用localhost连接到MySQL是非常慢的。

更改脚本中的mysql服务器地址为127.0.0.1解决了这个问题。

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

那么,原因是很明显的。 PHP真的很擅长一些东西,但不是直接把'localhost'翻译成'127.0.0.1'。 你必须这样做,它会真正降低你的整个网站的页面加载时间,因为它将PHP从检查你的HOSTS文件中拿回来,而不是在'localhost'之后得到真正的IP地址,

将此行添加到主机文件解决了我的问题

 127.0.0.1 localhost 

详细的答案可以在这个线程中find: https : //stackoverflow.com/questions/13584360/php-with-mysql-is-slow

你也可以通过对你的数据库连接variables进行一些小的调整来消除查询速度的减慢(为了便于携带,希望在你的脚本中有一个单独的文件)。 将主机值更改为“127.0.0.1”而不是“localhost”。 这绕过了localhost冗长的DNS查找。

希望这可以帮助!