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

PHP + MySQL 實現無限級分類:從遞歸到高效能方案

     編輯:PHP 綜合知識

無限級分類的常見挑戰

在電商、CMS 或論壇系統中,分類結構往往不止兩三層。傳統的「遞歸查詢」雖然直觀,但當分類數量增長到數千甚至上萬時,每次請求都要執行大量 SQL 查詢,效能會急劇下降。本文將介紹幾種主流的無限級分類實現方式,並附上可直接運行的資料表結構與範例代碼。

資料表結構(鄰接表模型)

最基本的設計是 class 表,使用 classid 指向父分類:

-- 表的結構 `class`
SET NAMES utf8;
CREATE TABLE `class` (
  `id` INT(10) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(250) CHARACTER SET utf8 DEFAULT NULL,
  `classid` INT(10) DEFAULT NULL,
  `sort` INT(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=11;

-- 範例資料
INSERT INTO `class` (`id`, `name`, `classid`, `sort`) VALUES
(1, '中國', 0, 1),
(2, '廣西', 1, 1),
(3, '桂林', 2, 2),
(4, '廣東', 1, 2),
(5, '北京', 1, 3),
(6, '東莞', 4, 10),
(7, '南寧', 2, 10),
(8, '陽朔', 3, 10),
(9, '柳州', 2, 10),
(10, '廣州', 4, 10);

方案一:遞歸查詢(適合小數據量)

優點:代碼簡單,邏輯清晰。
缺點:每層都要查一次資料庫,N+1 問題嚴重。

<?php
function getChildren($pdo, $parentId = 0) {
    $stmt = $pdo->prepare("SELECT * FROM `class` WHERE classid = ? ORDER BY sort");
    $stmt->execute([$parentId]);
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    foreach ($rows as &$row) {
        $row['children'] = getChildren($pdo, $row['id']);
    }
    return $rows;
}

方案二:一次性查詢 + PHP 組裝樹(推薦中型專案)

只查一次資料庫,在記憶體中用引用構建樹結構,效能提升數十倍。

<?php
function buildTree($pdo) {
    $stmt = $pdo->query("SELECT * FROM `class` ORDER BY sort");
    $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
    $tree = [];
    $map = [];
    foreach ($items as $item) {
        $map[$item['id']] = &$item;
        $item['children'] = [];
    }
    foreach ($items as $item) {
        if ($item['classid'] == 0) {
            $tree[] = &$item;
        } else {
            if (isset($map[$item['classid']])) {
                $map[$item['classid']]['children'][] = &$item;
            }
        }
    }
    return $tree;
}

方案三:路徑枚舉 / Closure Table(適合高頻讀取、深層結構)

在資料表中新增 path 欄位(如 0,1,2,3),或建立獨立的 class_closure 表記錄所有祖先後代關係。查詢子樹、移動節點都變成單條 SQL,極大提升讀寫效能。

效能對比建議

  • 分類 < 500、層級 < 4:遞歸或一次性組裝皆可。
  • 分類 500~5000、頻繁讀取:一次性查詢 + PHP 組裝最划算。
  • 分類 > 5000、需頻繁移動節點:採用 Closure Table 或 Nested Set。

實際專案中,建議結合 Redis 緩存整棵分類樹,僅在後台更新時重建緩存,讀取端完全走記憶體,效能最優。

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