首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 專案效能優化實戰:從千條 SQL 到單一 JOIN 的 26 倍加速

     編輯:PHP 綜合知識

問題背景

公司數個網站託管於美商虛擬主機,MySQL 服務幾乎每天莫名掛掉又自動恢復。雖然流量極低,但懷疑觸發 CPU 使用限制。服務商客服排查後保證非主機問題,只能自行深入調查。

定位瓶頸:開啟慢查詢日誌

在 my.ini 加入:

[mysqld]
log="d:/temp/mysql.log"
log_slow_queries="d:/temp/mysql_slow.log"
long_query_time=1

重啟 MySQL 後,發現隨意一頁就產生幾十至上千條查詢!正常論壇頁面約 10 條查詢,負擔放大數十倍,怪不得會掛。

罪魁禍首:N+1 迴圈查詢

以「顯示所有地區分類及其文章數」為例,原始碼:

$sql1 = "SELECT aid, count(*) as cc FROM pz_content WHERE uid=$uid GROUP BY aid";
$rs1 = $db->query($sql1);
if (is_array($rs1)) {
    foreach ($rs1 as $r1) {
        echo id2name($r1->aid); // 每迴圈一次查詢
    }
}

function id2name($aid) {
    $sql = "SELECT ename FROM pz_area_a WHERE aid_a=".$aid;
    $result = mysql_query($sql);
    $row = mysql_fetch_object($result);
    return $row->ename;
}

若有 1 萬個地區,就會執行 1 萬次查詢。實測:記憶體 6MB、耗時 16 秒、查詢 1001 次。

優化方案:單一 SQL + JOIN

$sql1 = "SELECT pz_area.aid, pz_area.ename, tb1.cc
         FROM pz_area
         RIGHT JOIN (
             SELECT aid, count(*) as cc FROM pz_content WHERE uid=$uid GROUP BY aid
         ) AS tb1 ON pz_area.aid = tb1.aid";

$rs1 = $db->query($sql1);
if (is_array($rs1)) {
    foreach ($rs1 as $r1) {
        echo $r1->ename; // 直接取得名稱,無需額外查詢
    }
}

成果驗證

指標優化前優化後再加索引
查詢次數100111
CPU 時間16 秒647 ms432 ms
記憶體6 MB≈6 MB≈6 MB

單純改寫 SQL 即達 26 倍加速;在 pz_content.aid 加索引後再提升 33%。

經驗總結

  1. 善用慢查詢日誌:long_query_time=1 快速定位問題語句。
  2. 拒絕迴圈查詢:能用 JOIN、子查詢 合併的,堅決不寫迴圈。
  3. 索引是放大器:優化 SQL 後,別忘在關鍵欄位(如外鍵、分組欄位)建立索引。
  4. MVC 分層的價值:邏輯與視圖分離,才容易發現並重構此類資料存取問題。

此頁面優化告一段落,後續將持續清理其他高負載頁面。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved