You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 5.5中如何统计用户自关联的5级子节点数量

解决方案:无需加载模型的5级子节点统计

嗨,针对你Laravel 5.5项目里的这个需求,我有两个高效的方案,完全不用加载任何用户模型实例,直接通过数据库查询拿到各层级的子节点数量,性能拉满!

方案一:使用递归CTE(推荐,MySQL 8+/PostgreSQL适用)

递归CTE可以一次性查询出所有层级的子节点,然后按层级分组统计数量,非常高效。你可以直接用DB门面来实现:

$userId = $user->id;

$levels = DB::select("
    WITH RECURSIVE user_hierarchy AS (
        SELECT id, parent_id, 1 AS level
        FROM users
        WHERE parent_id = ?
        UNION ALL
        SELECT u.id, u.parent_id, uh.level + 1 AS level
        FROM users u
        JOIN user_hierarchy uh ON u.parent_id = uh.id
        WHERE uh.level < 5
    )
    SELECT level, COUNT(*) AS count
    FROM user_hierarchy
    GROUP BY level
    ORDER BY level
", [$userId]);

// 格式化输出
foreach ($levels as $level) {
    echo "Level {$level->level}: {$level->count}\n";
}

说明:

  • 这个CTE会从指定用户的直接子节点(Level 1)开始,递归查询到第5级为止
  • 最后按层级分组统计数量,完全在数据库层面完成,不会加载任何User模型对象
  • 如果你的数据库是MySQL 5.x不支持CTE,看下面的方案二

方案二:分层左连接(兼容MySQL 5.x)

因为只需要统计到5级,我们可以通过多次左连接来分别查询每一层的节点,然后统计数量:

$userId = $user->id;

// Level 1:直接子节点
$level1 = DB::table('users')->where('parent_id', $userId)->count();

// Level 2:Level1节点的子节点
$level2 = DB::table('users as l1')
    ->join('users as l2', 'l2.parent_id', '=', 'l1.id')
    ->where('l1.parent_id', $userId)
    ->count();

// Level 3:Level2节点的子节点
$level3 = DB::table('users as l1')
    ->join('users as l2', 'l2.parent_id', '=', 'l1.id')
    ->join('users as l3', 'l3.parent_id', '=', 'l2.id')
    ->where('l1.parent_id', $userId)
    ->count();

// Level 4:Level3节点的子节点
$level4 = DB::table('users as l1')
    ->join('users as l2', 'l2.parent_id', '=', 'l1.id')
    ->join('users as l3', 'l3.parent_id', '=', 'l2.id')
    ->join('users as l4', 'l4.parent_id', '=', 'l3.id')
    ->where('l1.parent_id', $userId)
    ->count();

// Level 5:Level4节点的子节点
$level5 = DB::table('users as l1')
    ->join('users as l2', 'l2.parent_id', '=', 'l1.id')
    ->join('users as l3', 'l3.parent_id', '=', 'l2.id')
    ->join('users as l4', 'l4.parent_id', '=', 'l3.id')
    ->join('users as l5', 'l5.parent_id', '=', 'l4.id')
    ->where('l1.parent_id', $userId)
    ->count();

// 格式化输出
echo "Level 1: {$level1}\n";
echo "Level 2: {$level2}\n";
echo "Level 3: {$level3}\n";
echo "Level 4: {$level4}\n";
echo "Level 5: {$level5}\n";

说明:

  • 这个方法虽然写起来繁琐一点,但完全兼容不支持CTE的旧版本MySQL
  • 每一层的查询都是直接在数据库统计数量,不会加载任何模型对象,性能同样优秀

为什么你的原有代码不行?

你之前用的User::with('parent')->where('id','=', $user->id)->get()其实只拿到了当前用户自己和它的父节点,根本没查询子节点;就算你用with('children')递归加载,也会把所有子节点的模型实例加载到内存里,数据量大的时候性能会很差,这两个方案完美解决了这个问题。

内容的提问来源于stack exchange,提问作者addi2113

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:41:37