You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel批量生成HTML页面超时及性能优化求助

Laravel批量生成HTML页面的优化方案

核心问题分析

  • 全量加载+重复遍历:一次性把所有文章查进内存,每生成一页就遍历一遍全量数据,192页就要遍历192次,时间复杂度直接拉满,慢是必然的。
  • 手动分页逻辑混乱:靠desc_id范围+计数器判断分页,一旦desc_id有断层(比如删过文章),分页直接出错,而且两种分页判断逻辑重复,徒增耗时。
  • 运行环境错配:在web请求里跑长时间批量任务,HTTP默认60秒超时限制直接触发报错,web环境本来就不适合干这事。

优化方案

1. 用Laravel内置分页按需查数据

放弃全量查询,每一页只查对应8条数据,内存占用砍到原来的1/N,遍历次数也从192次全量变成192次单页查询,效率直接起飞。

2. 改用Artisan命令执行任务

命令行环境没有HTTP超时限制,适合处理这种长时间批量操作,还能实时看到进度。

3. 简化数据库查询条件

原查询里draft=0是两个分支的共同条件,提出来减少嵌套,让SQL更高效。

完整优化代码示例

第一步:创建Artisan命令

执行终端命令生成命令文件:

php artisan make:command GenerateArticlePages

然后修改app/Console/Commands/GenerateArticlePages.php:

<?php

namespace App\Console\Commands;

use App\Models\Article;
use App\Models\Page;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;

class GenerateArticlePages extends Command
{
    protected $signature = 'articles:generate-pages {--start=5}'; // 可通过参数修改起始页
    protected $description = '生成文章列表静态HTML页面';

    public function handle()
    {
        $homepage = Page::find(1);
        $perPage = 8;
        $startPage = $this->option('start');

        // 先算总页数,避免无效循环
        $totalArticles = Article::where('draft', 0)
            ->where(function ($query) {
                $query->whereNull('publication_date')
                    ->orWhere('publication_date', '<=', now());
            })
            ->count();
        $lastPage = ceil($totalArticles / $perPage);

        // 遍历生成每一页
        for ($i = $startPage; $i <= $lastPage; $i++) {
            // 只查当前页需要的8条数据
            $articles = Article::where('draft', 0)
                ->where(function ($query) {
                    $query->whereNull('publication_date')
                        ->orWhere('publication_date', '<=', now());
                })
                ->orderBy('publicated_at', 'DESC')
                ->skip(($i - 1) * $perPage)
                ->take($perPage)
                ->get();

            if ($articles->isEmpty()) {
                $this->info("第{$i}页无文章,跳过");
                continue;
            }

            // 渲染视图并写入文件
            $html = view('allArticlesTemplate')->with([
                "articles" => $articles,
                "homepage" => $homepage,
                "this_page" => $i,
                "last_page" => $lastPage
            ])->render();

            $filePath = resource_path("views/allArticlesHtml/page{$i}.html");
            File::put($filePath, $html);

            $this->info("已生成第{$i}页:{$filePath}");
        }

        $this->info("所有页面生成完成!");
    }
}

第二步:执行命令

在终端运行:

php artisan articles:generate-pages

如果需要修改起始页(比如从第10页开始):

php artisan articles:generate-pages --start=10

额外优化建议

  • 缓存查询结果:如果文章更新不频繁,把总页数和单页文章数据缓存起来,减少数据库查询次数。
  • 队列异步处理:页数特别多的话,把每一页生成任务丢进队列,多进程并行处理,速度再翻倍。
  • 错误捕获:加try-catch块,避免单个页面生成失败导致整个任务中断。
  • 批量IO:先把HTML写入临时文件,全部生成完再统一移动到目标目录,减少磁盘IO次数。

内容的提问来源于stack exchange,提问作者Tammapao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 17:45:37