Laravel多JSON文件读取性能问题及优化方案咨询
兄弟,你现在这个把每次变更存单独JSON文件的方案,说实话从长期来看真的不太合理,检索慢就是最直接的问题,咱们来掰扯掰扯为啥,以及Laravel里有啥更靠谱的办法。
当前方案的核心问题
- IO性能瓶颈:文件系统处理大量小文件的效率本来就低,当变更记录多了之后,遍历文件、打开读取的开销会直线上升——尤其是你要查某条记录的所有变更时,得挨个找对应文件,耗时肯定扛不住。
- 维护成本高:大量零散的JSON文件不好管理,备份、迁移、清理旧数据都很麻烦,而且没法直接做复杂查询(比如按时间范围筛选某类模型的变更,或者找某个用户修改的记录)。
- 版本追踪不便:要对比某条记录的多次变更,得打开多个文件手动对比,远不如结构化存储方便。
Laravel里的更优实现方式
最推荐的是基于数据库的审计日志方案,不管是自己手动实现,还是用成熟的第三方包,都比文件方案高效太多。
1. 手动实现基础审计日志
步骤很清晰,完全贴合Laravel的Eloquent生态:
- 首先创建审计日志表,执行这个迁移:
Schema::create('model_audits', function (Blueprint $table) { $table->id(); $table->string('model_type'); // 对应模型类名,比如App\Models\Post $table->unsignedBigInteger('model_id'); $table->json('old_values')->nullable(); // 变更前的字段值 $table->json('new_values')->nullable(); // 变更后的字段值 $table->unsignedBigInteger('user_id')->nullable(); // 操作人ID(可选) $table->enum('action', ['created', 'updated', 'deleted']); $table->timestamps(); // 添加索引优化查询速度 $table->index(['model_type', 'model_id']); $table->index('user_id'); });
- 然后在需要追踪的模型里注册事件,比如在
App\Models\Post的boot方法里:
protected static function boot() { parent::boot(); // 记录创建事件 static::created(function ($post) { ModelAudit::create([ 'model_type' => get_class($post), 'model_id' => $post->id, 'new_values' => $post->getAttributes(), 'action' => 'created', 'user_id' => auth()->id(), // 可选,记录当前登录用户 ]); }); // 记录更新事件(只存变化的字段) static::updated(function ($post) { $changes = array_diff_assoc($post->getAttributes(), $post->getOriginal()); if (!empty($changes)) { ModelAudit::create([ 'model_type' => get_class($post), 'model_id' => $post->id, 'old_values' => $post->getOriginal(array_keys($changes)), 'new_values' => $changes, 'action' => 'updated', 'user_id' => auth()->id(), ]); } }); // 记录删除事件 static::deleted(function ($post) { ModelAudit::create([ 'model_type' => get_class($post), 'model_id' => $post->id, 'old_values' => $post->getAttributes(), 'action' => 'deleted', 'user_id' => auth()->id(), ]); }); }
之后查询某条记录的变更历史就简单到离谱:
$post = Post::find(1); $history = ModelAudit::where('model_type', get_class($post)) ->where('model_id', $post->id) ->orderBy('created_at', 'desc') ->get();
数据库有索引加持,查询速度快得飞起,还能轻松做各种筛选、排序。
2. 用成熟的第三方包(更省心)
如果不想自己写重复代码,直接用spatie/laravel-activitylog这个包——Laravel生态里最流行的审计日志工具之一,开箱即用:
- 安装包:
composer require spatie/laravel-activitylog
- 发布迁移文件并执行:
php artisan vendor:publish --provider="Spatie\Activitylog\ActivitylogServiceProvider" --tag="migrations" php artisan migrate
- 在需要追踪的模型里添加
LogsActivitytrait,配置要记录的字段:
use Spatie\Activitylog\Traits\LogsActivity; class Post extends Model { use LogsActivity; // 配置要记录的字段,默认记录所有字段变更 protected static $logAttributes = ['title', 'content']; // 只记录有变化的字段 protected static $logOnlyDirty = true; // 自定义日志名称,方便区分不同模型 protected static $logName = 'post'; }
之后所有变更都会自动存入activity_log表,查询历史也很简单:
$post = Post::find(1); $history = $post->activities()->orderBy('created_at', 'desc')->get();
这个包还支持自定义日志内容、关联用户、批量清理旧日志等功能,省心又省力。
总结
当前的单JSON文件方案只适合非常小规模的场景,一旦数据量上来,检索和维护都会出问题。Laravel里用数据库存储审计日志才是更合理的选择,不管是手动实现还是用第三方包,都能解决你现在的检索慢问题,而且扩展性更强。
内容的提问来源于stack exchange,提问作者Kanth
相关产品推荐
相关产品推荐

