1 回答
TA贡献1886条经验 获得超2个赞
这个问题及其潜在的问题引起了我的兴趣,所以我想了解更多关于整个问题的信息。我自己创建了一个测试场景。
优化
首先对刀片模板的代码进行一些优化:
// index.blade.php
<select>
@include('categories.options', ['categories' => $categories, 'level' => 0])
</select>
// options.blade.php
@foreach ($categories as $category)
<option value="{{ $category->id }}">{{ str_repeat("--", $level) }} {{ $category->name }}</option>
@include('categories.options', ['categories' => $category->categories, 'level' => $level+1])
@endforeach
然后,我生成了一个包含大约 5000 个嵌套类别、8 层深度的数据库,以测试加载时间。我的假设是,如果您向类别模型添加急切加载,则可以优化加载时间:
// Category.php
// this eager loads ALL nested relations using levels + 1 queries
protected $with = ['categories'];
// this is not needed and doesn't make any difference
protected $with = ['categories.categories'];
结果如下:
Time Queries Memory
--------------------------------------------------
No eager loading 12,81 s 5101 112MB
with eager loading 1,49 s 9 31MB
2 x eager loading 1,54 s 9 31MB
Caching 0,08 s 0 4MB
(stats recorded mainly with debugbar)
正如您所看到的,急切加载绝对是有意义的。在模型中放入一个单一的关系也足够了$with = ['categories'],laravel 将立即加载所有嵌套的关系 - 整洁!
缓存
因此,为了让网站尽可能快地加载(我能想到的),唯一真正的解决方案是缓存。
// create new job in console
php artisan make:job RenderCategoryView
// RenderCategoryView.php
public function handle() {
// get all top level categories
$categories = \App\Category::where('category_id', null)->get();
$html = \View::make('categories.options', ['categories' => $categories, 'level' => 0])->render();
file_put_contents(resource_path('views/categories/options_cache.blade.php'), $html);
return true;
}
@include现在您可以像这样替换刀片模板:
// index.blade.php
@include('categories.options_cache')
要测试 options_cache 文件的生成,您可以执行以下操作:
php artisan tinker
\App\Jobs\RenderCategoryView::dispatchNow();
我还在返回索引视图之前删除了现在不必要的数据库查询,新的加载时间为83 ms。这并不奇怪,因为现在所有内容都被缓存了。
要在创建、编辑或删除类别后自动生成新的视图缓存,您应该将其包含在相应的控制器中:
\App\Jobs\RenderCategoryView::dispatch();
- 1 回答
- 0 关注
- 95 浏览
添加回答
举报