萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

樹狀論壇遞歸效能優化:以 mysql_data_seek 取代全表掃描

問題背景

傳統樹狀論壇(如 BBS)在顯示巢狀回覆時,常採用遞歸查詢整張資料表,隨著資料量增長,效能急劇下降。本文提出一種「先取根主題,再以 mysql_data_seek 在單一結果集中跳躍游標」的策略,大幅減少資料庫往返次數,提升顯示速度。

資料表設計

newestbbs(最新主題索引表)

欄位說明
id根主題 ID
time最後回覆時間(無回覆則為發文時間)

bbs(完整文章表)

欄位說明
id文章本身 ID
fathered父文章 ID
rootid根主題 ID
time發文時間
...其他欄位

優化邏輯

  1. 從 newestbbs 取得最新 20 筆根主題 ID(分頁)。
  2. 對每個根主題 ID,從 bbs 撈取所有 rootid 相符的文章,按時間排序,一次性取回完整結果集 $res。
  3. 利用 mysql_data_seek($res, $row) 移動記錄指標,避免重複查詢。

核心程式碼

<?php
// 取得最新主題列表
$listRes = mysql_query("SELECT id FROM newestbbs ORDER BY time LIMIT $offset, 20");

while ($topic = mysql_fetch_assoc($listRes)) {
    $rootId = $topic['id'];
    // 一次撈取該主題所有回覆
    $res = mysql_query("SELECT * FROM bbs WHERE rootid=$rootId ORDER BY time");
    
    // 顯示根主題
    $root = mysql_fetch_assoc($res);
    displayTopic($root);
    
    // 遞歸顯示回覆,傳入結果集資源
    displayReplies($root['id'], $res);
}

function displayReplies($parentId, $resultResource) {
    $total = mysql_num_rows($resultResource);
    for ($i = 0; $i < $total; $i++) {
        mysql_data_seek($resultResource, $i);
        $row = mysql_fetch_assoc($resultResource);
        if ($row['fathered'] == $parentId) {
            displayTopic($row);
            displayReplies($row['id'], $resultResource); // 遞歸
        }
    }
}
?>

關鍵函數:mysql_data_seek

bool mysql_data_seek(resource $result, int $row_number) 允許將結果集的內部指標移動到指定列號(0 起算)。這意味著我們可以在同一結果集中反覆跳轉,模擬多次查詢的效果,卻只需一次資料庫連線。

效能比較

指標傳統遞歸查詢本法(單查詢 + 游標跳躍)
資料庫往返次數O(N) 次(N 為節點數)1 次(每主題)
記憶體用量低中(需載入整主題結果集)
適用規模小型論壇中大型、高頻讀取場景

注意事項

  • 結果集不宜過大,建議單一主題回覆數在數千筆以內;超大主題仍建議分頁或改用巢狀集合模型。
  • 本範例使用已棄用的 mysql_* 函數,實務上請改用 mysqli 或 PDO,邏輯不變。
copyright © 萬盛學電腦網 all rights reserved