使用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
相关产品推荐
相关产品推荐

