Windows

從 PHP 連接到 MySQL 非常慢

  • December 30, 2017

我剛剛重新安裝了 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 程式碼和靜態文件的提供比我點擊刷新要快。我通過執行這個小腳本來測試 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 工作台即時連接

是不是您的 mysql 在您連接時嘗試執行 rev-dns 查詢?嘗試添加到 my.cnf 部分 mysqld: skip-name-resolve

這幾乎是從我在這裡的回答中逐字記錄的,但我知道我們對 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,解析內置於 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=命令行參數啟動 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 連接。

我需要修改hosts文件嗎?

沒有。不要修改主機文件。DNS 解析器知道如何處理localhost,重新定義它充其量是沒有效果的,最壞的情況是把解析器弄得一團糟。

怎麼樣--skip-name-resolve

由於相關但略有不同的原因,這也可以解決問題。

如果沒有此配置選項,MySQL 將嘗試通過PTRDNS 查詢將所有客戶端連接 IP 地址解析為主機名。如果您的 MySQL 伺服器已經啟用了使用 IPv6,但連接仍然需要很長時間,可能是因為反向 DNS ( PTR) 記錄配置不正確。

禁用名稱解析將解決此問題,但它確實有其他後果,特別是配置為在條件下使用 DNS 名稱的任何訪問權限Host現在都將失敗。

如果您要這樣做,您需要將所有授權配置為使用 IP 地址而不是名稱。

引用自:https://serverfault.com/questions/408550