将PHP连接到EasyPHP MySQL服务器时出现1秒延迟的问题

14

我在这里提问是因为我认为这不仅适用于EasyPHP本身。

目前,我使用EasyPHP作为我的WAMP开发服务器,以便创建Web应用程序。问题在于,当我获取mysqli对象连接到数据库时,它需要1秒钟的时间。 在共享托管上运行相同的查询会导致速度快200倍以上。这是我应该担心的事情吗?在可扩展性或将应用程序移动到另一台服务器方面,是否明智花些时间来查找问题所在?我只是假设可能EasyPHP很慢。这不是什么大问题,只是让我感到有趣。

3个回答

57
如果您遇到此问题并且使用的是 Windows 7 之前的版本,则这可能不是解决问题的方法。
为什么会发生这种情况?
这个问题的原因是 IPv4 和 IPv6。
当您使用主机名而不是 IP 地址时,MySQL 客户端首先运行一个 AAAA(IPv6)主机查找名称,并在成功将名称解析为 IPv6 地址时首先尝试此地址。如果任一步骤失败(名称解析或连接),它将回退到 IPv4,运行 A 查找并尝试使用此主机。
实际上,这意味着如果 IPv6 的 localhost 查找成功但 MySQL 没有绑定到 IPv6 回环,则需要等待一个连接超时周期(显然在 OP 的机器上这是 1 秒钟)才会发生 IPv4 回退并成功连接。
在 Windows 7 之前,这不是问题,因为 localhost 解析是通过 hosts 文件完成的,并且预配置了只有 127.0.0.1 - 它没有带有其 IPv6 对应项 ::1。
自从Windows 7以来,DNS解析器内置了localhost解析功能,原因在这里概述。这意味着IPv6查找现在将成功,但是MySQL未绑定到该IPv6地址,因此连接将失败,并且您将看到本问题中概述的延迟。
你有几个选项。在互联网上查找,一般的“解决方案”似乎是明确使用IP地址而不是名称,但有几个原因不这样做,都与可移植性相关,都可以说不重要:
- 如果您将脚本移动到仅支持IPv6的另一台机器上,则您的脚本将不再起作用。 - 如果您将脚本移动到基于*nix的托管环境中,则魔术字符串localhost将意味着MySQL客户端优先使用Unix套接字(如果已配置),这比基于IP环回的连接更高效。
它们听起来很重要吗?
他们并不是最佳选择。您应该设计应用程序,以便这种类型的事情在配置文件中定义。如果您将脚本移动到另一个环境,则很可能需要配置其他内容。
总之,使用IP地址不是最好的解决方案,但很可能是可接受的解决方案。
那么什么是最佳解决方案呢?
最好的方法是更改MySQL服务器使用的绑定地址。然而,这并不像人们想象的那样简单。与Apache、Nginx和几乎所有其他合理的网络服务应用程序不同,MySQL只支持单个绑定地址,因此不仅仅是添加另一个绑定地址的问题。不过,幸运的是,操作系统在这里支持一些魔法,因此我们可以同时启用MySQL使用IPv4和IPv6。
您需要运行MySQL 5.5.3或更高版本,并使用命令行参数--bind-address=(或在my.ini中设置相应选项)启动MySQL。根据您想要做什么,您有4个选项docs
  • 您可能熟悉的是,也是您最有可能(有效地)使用的是0.0.0.0。这将绑定到计算机上所有可用的IPv4地址。即使您不关心IPv6,这实际上可能并不是最好的选择,因为它与::具有相同的安全风险。

  • 显式的IPv4或IPv6地址(例如127.0.0.1::1用于环回)。这会将服务器绑定到该地址,该地址。

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

  • 使用IPv4-mapped IPv6 address。这是IPv6中内置的一种特殊机制,用于在4 -> 6转换期间进行向后兼容,并允许您绑定到特定的IPv4地址及其IPv6等效地址。除了“双环回”地址::ffff:127.0.0.1之外,这几乎不可能对您有用。这对于大多数人来说可能是最好的解决方案,只绑定到环回但允许IPv4和IPv6连接。

我需要修改hosts文件吗?

不需要。DNS解析器知道如何处理localhost,重新定义它最多没有效果,最坏的情况会让解析器混乱不堪。

--skip-name-resolve呢?

出于相关但略有不同的原因,这也可能修复问题/需要修复问题。

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

禁用名称解析将解决此问题,但它确实有其他影响,特别是任何配置为在Host条件中使用DNS名称的访问权限现在将失败。

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


太长不看!哈哈,实际上,这个答案很完美。你知道MySQL 5.6是否解决了这个问题吗?我可能会升级。 (但是,说真的,没有jQuery吗?) - MaxArt
这似乎是Windows 8机器上出现非常慢的mysql查询的一个非常普遍的问题(SEO评论)。 - Josiah
我晚了2年,但我刚刚把采纳的答案改成了你的。谢谢。 - Sam
简而言之,在开发机器上,打开my.ini文件并设置:bind-address=::(可选择让防火墙阻止远程访问)。 - marcovtwout
这个救了我的命!如果你在Docker容器中运行MySQL,请确保在你的[mysqld]配置文件中有skip-host-cacheskip-name-resolve这两行。响应时间从4~5秒降至0.02毫秒。 - Shinebayar G

28

当我使用localhost作为MySQL服务器地址时,遇到了一些延迟。将其更改为127.0.0.1有所帮助。


好的,你太棒了。非常感谢你。我把主机改成了127.0.0.1,我的页面执行时间只有0.0074560547秒。无法感谢你的足够。 - Sam

0
无论服务器如何,尽可能使用持久连接总是很好的。毕竟,如果旧连接也能完成工作,那么一直打开新连接是不明智的。请查看 mysqli 的{{manual}}。

我曾遇到过持久连接的问题 - PHP有时会尝试创建新的连接,尽管已经存在“空闲”的连接,这导致了“连接过多”错误。虽然这是几年前的事情,但现在可能已经解决了(或者甚至可能是本地问题)。 - binaryLV
它一定已经被修复了。mysqli的持久连接是在PHP 5.3中引入的,因此它们并不是那么古老。 - linepogl
我相信我遇到了PDO或旧的mysql函数的问题。从未真正使用过mysqli。 - binaryLV
我在脚本开始时打开连接,在结束时关闭它。那不是一个持久连接吗? - Sam
阅读手册,我不太喜欢持久连接的外观。 - Sam
@Sam,不,这不是持久的。 持久连接甚至在脚本结束后也可以被重复使用。 - linepogl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接