Laravel共享全局搜索数据时产生大量重复查询问题排查
重复查询原因
- 视图合成器使用
*通配符匹配所有视图,每渲染一个视图(包括布局、子组件、嵌套视图)都会触发一次回调,页面如果涉及90个视图渲染,就会执行90次GlobalSearch查询逻辑。 GlobalSearch类未做结果缓存,每次调用all()方法都会重新执行SQL查询,没有复用已查询到的结果。- 冗余写法问题:
View::share本身是全局共享视图变量的方法,不需要放在视图合成器中重复执行,进一步放大了重复调用的问题。
排查步骤
- 临时注释视图合成器代码,在单个控制器中手动调用一次
GlobalSearch的all()方法,确认查询次数是否为1,验证是否为视图合成器重复触发导致的问题。 - 在
propertyData()方法中添加日志,统计方法被调用的次数,确认调用次数和重复查询次数是否匹配,定位触发来源。 - 统计当前页面渲染的视图总数,确认视图数量是否等于90,验证通配符触发逻辑的猜想。
修复方案
1. 调整视图变量共享逻辑
移除通配符视图合成器,将全局变量共享逻辑改成仅在请求生命周期内执行一次:
public function boot() { $this->app->resolving(function () { if (auth()->check() && optional(auth()->user())->currentTeam) { \View::share('SearchData', (new GlobalSearch(auth()->user()->currentTeam))->all()); } }); }
如果不需要全局所有视图都用到SearchData,也可以指定视图合成器的匹配路径,不要用*通配符。
2. 为GlobalSearch增加查询缓存
在类中增加缓存属性,避免重复执行查询:
class GlobalSearch { // 存储已查询的结果 protected ?array $cachedResult = null; public $data; public function __construct(public Team $team){ $this->data = $team->properties()->with(['leases', 'leases.tenant', 'leases.files', 'leases.invoices']); } protected function propertyData() : array { // 已有缓存直接返回 if (!is_null($this->cachedResult)) { return $this->cachedResult; } $properties = $this->data->get(); $this->cachedResult = $properties->map(function ($property) { $array['name'] = \Str::limit($property->address, 40); $array['url'] = route('properties.show', ['property' => $property]); return $array; })->toArray(); return $this->cachedResult; } public function all() : array { return $this->propertyData(); } }
内容的提问来源于stack exchange,提问作者oliverbj
相关产品推荐
相关产品推荐

