FilamentPHP v3中Repeater内Select字段内存耗尽问题求优化方案
优化FilamentPHP v3中Repeater内Select字段内存耗尽问题
针对你遇到的2万条产品数据导致内存不足的问题,以下是具体优化方案:
1. 移除preload(),启用异步搜索
preload()会一次性把所有选项加载到内存,这是内存耗尽的核心原因。Filament的searchable()默认支持异步搜索,删掉preload()后,仅当用户输入搜索关键词时才会触发数据库查询,不会预加载全量数据。
2. 用searchUsing()实现精准异步搜索
自定义搜索逻辑,只返回匹配关键词的结果,同时限制返回条数,避免一次性加载过多数据:
Select::make('product_id') ->hidden(function () use ($productId) { return $productId !== null; }) // 替换原options方法,改用searchUsing实现异步搜索 ->searchUsing(function (Get $get, string $search) { $supplierId = $get('../../supplier_id'); if (!$supplierId) { return ['Selecteer eerst een merk']; } return Product::select('id', DB::raw("CONCAT(item_code, ' - ', item_description) as concatenated_value")) ->where('supplier_id', $supplierId) ->where('available', true) // 模糊匹配搜索关键词,可根据实际字段调整 ->where(function ($query) use ($search) { $query->where('item_code', 'like', "%{$search}%") ->orWhere('item_description', 'like', "%{$search}%"); }) ->limit(50) // 限制返回最多50条结果 ->pluck('concatenated_value', 'id') ->toArray(); }) ->label('Product') ->searchable() // 移除preload() ->disabled(fn(Get $get) => $get('../../sent')) ->columnSpan(2) ->required();
3. 数据库层面优化查询速度
给查询用到的字段添加索引,减少数据库查询时间和内存占用:
-- 给supplier_id、available添加复合索引 CREATE INDEX products_supplier_available ON products (supplier_id, available); -- 给item_code和item_description添加全文索引(提升模糊搜索效率) ALTER TABLE products ADD FULLTEXT INDEX idx_products_search (item_code, item_description);
如果使用全文索引,搜索逻辑可改为:
->whereRaw("MATCH(item_code, item_description) AGAINST(? IN BOOLEAN MODE)", [$search])
4. 缓存供应商对应的产品列表
如果同一供应商的产品不会频繁变动,用Laravel缓存缓存查询结果,避免重复查询数据库:
->searchUsing(function (Get $get, string $search) { $supplierId = $get('../../supplier_id'); if (!$supplierId) { return ['Selecteer eerst een merk']; } // 缓存key,结合supplier_id和搜索关键词 $cacheKey = "products_supplier_{$supplierId}_search_{$search}"; return Cache::remember($cacheKey, now()->hour(), function () use ($supplierId, $search) { return Product::select('id', DB::raw("CONCAT(item_code, ' - ', item_description) as concatenated_value")) ->where('supplier_id', $supplierId) ->where('available', true) ->where(function ($query) use ($search) { $query->where('item_code', 'like', "%{$search}%") ->orWhere('item_description', 'like', "%{$search}%"); }) ->limit(50) ->pluck('concatenated_value', 'id') ->toArray(); }); })
5. 优化Repeater的加载逻辑
如果Repeater允许添加多个条目,每个条目都触发查询会成倍消耗内存。前面的异步搜索已经能大幅降低这个问题的影响,也可以额外判断:仅当当前条目未选定product_id时,才启用搜索功能。
内容的提问来源于stack exchange,提问作者sanders
相关产品推荐
相关产品推荐

