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

使用kalnoy/nestedset包时查询过慢的优化问题(Laravel 8)

优化kalnoy/nestedset分类查询的方案

针对你遇到的descendantsAndSelf()->pluck('id')查询耗时过高的问题,结合nestedset的特性和你的场景,给出以下优化方案:

  • 只查询需要的字段,避免select *
    底层第二个查询默认返回全表字段,但你仅需要id,显式指定查询字段可大幅减少数据库返回的数据量,降低IO和传输开销。修改代码为:

    $this->descendantsAndSelf($this->id)->select('id')->pluck('id');
    

    对应的底层查询会变为select id from categories where categories._lft between ? and ?,避免了不必要的字段读取。

  • 合并两次查询为单次子查询
    默认的descendantsAndSelf会先查询当前节点的_lft和_rgt,再发起范围查询。通过子查询合并成单次请求,减少数据库往返次数:

    $ids = DB::table('categories')
        ->whereBetween('_lft', function ($query) {
            $query->selectRaw('_lft, _rgt')
                  ->from('categories')
                  ->where('id', $this->id);
        })
        ->pluck('id');
    

    这种方式将两次查询合并为一次,消除了两次请求的网络延迟和连接开销。

  • 验证索引的实际执行效果
    虽然你已建立索引,但建议用EXPLAIN分析查询计划,确认_lft索引是否被正确使用:

    EXPLAIN SELECT id FROM categories WHERE _lft BETWEEN 357 AND 1400;
    

    查看结果中的type列应为range,key列应为_lft对应的索引。如果索引未被使用,检查字段类型是否匹配(比如_lft是否为整数类型),或是否存在索引失效的情况(如查询条件包含函数操作)。

  • 缓存查询结果
    分类层级结构通常不会频繁变动,利用Laravel缓存将结果持久化,避免重复查询:

    use Illuminate\Support\Facades\Cache;
    
    $cacheKey = 'category_descendants_ids_' . $this->id;
    $ids = Cache::remember($cacheKey, 3600, function () {
        return $this->descendantsAndSelf($this->id)->select('id')->pluck('id');
    });
    

    缓存有效期可根据你的更新频率调整,后续请求直接读取缓存,耗时可降至毫秒级。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 22:10:49