我刚刚安装了全新的 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 速度极慢的资料。
感谢任何能帮助我解决这个问题的人!
我正在使用适用于 win32 的 XAMPP 1.8.0(下载链接)
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 工作台可立即连接
答案1
是不是每次连接时,mysql 都会尝试运行 rev-dns 查询?尝试在 my.cnf 中添加 mysqld 部分:跳过名称解析。
答案2
这几乎逐字逐句地摘自我的回答这里但是我知道我们不赞成在 SO 上只提供链接的答案,所以我想你们也一样:-)
如果您遇到此问题并且使用 Windows 7 之前的 Windows 版本,这可能不是解决您的问题的答案。
为什么会发生这种情况?
造成该问题的原因是 IPv4 与 IPv6。
当您使用主机名而不是 IP 地址时,MySQL 客户端首先AAAA
针对该名称运行 (IPv6) 主机查找,如果成功将该名称解析为 IPv6 地址,则首先尝试此地址。如果任一步骤(名称解析或连接)失败,它将回退到 IPv4,运行查找A
并尝试此主机。
这在实践中意味着,如果 IPv6localhost
查找成功但 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 个选项文档,取决于你想做什么:
您可能熟悉并且最有可能(有效)使用的那个是 。
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 连接。
我需要修改hosts文件吗?
不。不要修改 hosts 文件。DNS 解析器知道如何处理localhost
,重新定义它充其量不会产生任何影响,最坏的情况是让解析器感到困惑。
关于什么--skip-name-resolve
?
出于相关但略有不同的原因,这也可能解决问题。
如果没有此配置选项,MySQL 将尝试通过 DNS 查询将所有客户端连接 IP 地址解析为主机名PTR
。如果您的 MySQL 服务器已启用 IPv6 但连接仍然需要很长时间,则可能是因为反向 DNS ( PTR
) 记录配置不正确。
禁用名称解析将解决此问题,但它确实有其他后果,特别是在条件中配置为使用 DNS 名称的任何访问权限Host
现在都将失败。
如果您要这样做,您将需要将所有授权配置为使用 IP 地址而不是名称。
答案3
通常,当服务器上启用 IPv6 时,与 MySQL 的连接速度localhost
会非常慢。
更改脚本中的 mysql 服务器地址即可127.0.0.1
解决问题。
答案4
将这一行添加到您的 hosts 文件中解决了我的问题
127.0.0.1 localhost
详细答案可以在此主题中找到: https://stackoverflow.com/questions/13584360/php-with-mysql-is-slow