Laravel 8在Mint系统中出现Symfony执行超时错误求助(关联polyfill-mbstring)
解决Laravel 8项目在Mint系统的超时问题
首先,虽然错误提示显示在symfony/polyfill-mbstring/Mbstring.php的632行,但这只是超时发生的“现场”,真正的根源是你的控制器代码存在大量低效的数据库查询(N+1查询问题),而Mint系统的PHP默认max_execution_time限制可能比Ubuntu更严格,所以触发了超时。下面分临时解决方案和根本优化方案来说:
一、临时应急:调整PHP执行时间限制
如果需要快速让项目运行起来,可以先修改PHP的执行时间配置:
- 找到你的PHP配置文件:在终端执行
php --ini,找到Loaded Configuration File对应的路径(比如/etc/php/8.0/cli/php.ini) - 编辑该文件,找到
max_execution_time配置项,把默认的60改成120甚至更高(比如max_execution_time = 120) - 如果你用的是Laravel内置开发服务器,重启服务器即可生效;如果用的是Nginx/Apache,需要重启对应的服务
或者也可以在控制器开头临时设置:
ini_set('max_execution_time', 120); // 设置为120秒
不过这只是权宜之计,随着数据量增长,超时问题还会再次出现,所以必须优化代码。
二、根本解决方案:优化数据库查询
你的控制器代码里存在多处循环嵌套数据库查询的情况,每一次循环都会发起新的数据库请求,这会导致执行时间指数级增长。下面针对你的代码逐一优化:
1. 优化日期去重逻辑
原来的代码通过PHP循环去重日期,改成直接在数据库层面分组去重:
$compressed_date = Report::where('store_id', $store->id) ->whereBetween('created_at', [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()]) ->selectRaw('DATE(created_at) as created_at') ->distinct() ->get() ->map(function($item) { return [ 'created_at' => $item->created_at, 'formated' => Carbon::parse($item->created_at)->format('m/d/Y') ]; });
2. 优化周产品统计逻辑
原来的map方法里每个Report都发起一次查询,改成一次性分组统计所有SKU的周总量:
use Illuminate\Support\Facades\DB; // 1. 一次性统计本周每个SKU的总数量 $weeklySkuCounts = Report::where('store_id', $store->id) ->whereBetween('created_at', [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()]) ->select('product_sku', DB::raw('COUNT(*) as weekly_amount')) ->groupBy('product_sku') ->get() ->keyBy('product_sku'); // 2. 一次性获取每个SKU对应的产品信息 $skuProductDetails = Report::where('store_id', $store->id) ->whereBetween('created_at', [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()]) ->select('product_name', 'product_variant', 'product_sku') ->distinct() ->get() ->keyBy('product_sku'); // 3. 合并成需要的数组 $compressed_weekly_product = collect(); foreach ($weeklySkuCounts as $sku => $countData) { $product = $skuProductDetails[$sku]; $compressed_weekly_product->push([ 'product_name' => $product->product_name, 'product_variant' => $product->product_variant, 'product_sku' => $sku, 'weekly_amount' => $countData->weekly_amount ]); }
3. 优化每日数量统计逻辑
原来的双重循环里每次都发起查询,改成一次性获取所有SKU的每日数据:
// 获取所有需要统计的日期 $targetDates = $compressed_date->pluck('created_at')->toArray(); // 一次性查询所有SKU的每日数量 $dailySkuStats = Report::where('store_id', $store->id) ->whereBetween('created_at', [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()]) ->select('product_sku', DB::raw('DATE(created_at) as date'), DB::raw('COUNT(*) as daily_count')) ->groupBy('product_sku', 'date') ->get() ->groupBy('product_sku'); // 填充每个SKU的每日数量 $compressed_weekly_product = $compressed_weekly_product->map(function($item) use ($dailySkuStats, $targetDates) { $skuDailyData = $dailySkuStats->get($item['product_sku'], collect()); $dailyAmount = []; foreach ($targetDates as $date) { // 找不到对应日期的数据就填0 $dailyAmount[] = $skuDailyData->where('date', $date)->first()?->daily_count ?? 0; } $item['daily_amount'] = $dailyAmount; return $item; });
4. 优化视图统计数据的获取
原来用sizeof(Model::get())的方式会把所有数据加载到内存再统计,改成用数据库的count()方法:
return view('panel.outlet.dashboard.index', [ 'is_dashboard'=>true, 'total_customer'=>Customer::where('store_id',$store->id)->count(), 'total_revenue'=>Order::where('store_id',$store->id)->whereIn('status',['2','3','-'])->sum('total_amount'), 'total_order'=>Order::where('store_id',$store->id)->count(), 'total_sales'=>Order::where('store_id',$store->id)->whereIn('status',['2','3','-'])->count(), 'total_product'=>Product::where('store_id',$store->id)->count(), 'total_sales_income'=>Order::where('store_id',$store->id)->whereIn('status',['2','3','-'])->sum('total_amount'), 'growth_percentage'=>round($growth_percentage,2), 'lastest_order'=>Order::where(['store_id'=>$store->id,'type'=>'app'])->orderBy('id','DESC')->limit(10)->get(), 'report_date'=>$compressed_date, 'top_weekly_product'=>$top_weekly_product, 'weekly_product'=>$compressed_weekly_product, 'weekly_report'=>DailyReport::where('store_id',$store->id)->whereBetween('created_at', [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()])->get() ]);
三、额外建议
- 可以开启Laravel的查询日志(
DB::enableQueryLog()),对比优化前后的查询数量,直观看到优化效果 - 给常用的查询字段(比如
store_id、product_sku、created_at)添加数据库索引,进一步提升查询速度
经过这些优化后,你的代码执行时间会大幅降低,无论是在Mint还是Ubuntu系统上都能流畅运行。
内容的提问来源于stack exchange,提问作者Aditya Rizqi
相关产品推荐
相关产品推荐

