本文目录导读:

在 Laravel 中,可以使用分区表进行归档,但这通常需要你手动实现或在数据库层面做配置,因为 Laravel 的 Eloquent ORM 和 Schema Builder 默认不直接提供分区表的管理功能。
有以下几种常见方案:
使用分区表归档(推荐)
如果你有大量数据(如日志、操作记录),按时间分区是最常见的归档方式。
实现方式:
- 数据库层面:在迁移文件中使用原生 SQL 创建分区表(例如按月分区)。
// database/migrations/xxxx_create_logs_table.php public function up() { DB::statement(' CREATE TABLE logs ( id BIGINT UNSIGNED AUTO_INCREMENT, content TEXT, created_at TIMESTAMP, PRIMARY KEY (id, created_at) ) PARTITION BY RANGE (TO_DAYS(created_at)) ( PARTITION p202301 VALUES LESS THAN (TO_DAYS("2023-02-01")), PARTITION p202302 VALUES LESS THAN (TO_DAYS("2023-03-01")), ... ); '); } - 归档操作:直接 truncate 或 drop 旧分区(这比 DELETE 快得多)。
// 删除 2023 年之前的分区 DB::statement('ALTER TABLE logs TRUNCATE PARTITION p2022'); // 或者直接删除分区(同时删除数据) DB::statement('ALTER TABLE logs DROP PARTITION p2022');
优点:
- 删除大量旧数据极快(毫秒级)。
- 查询时自动仅扫描相关分区,性能更好。
- 对业务代码几乎透明。
缺点:
- 迁移文件不好写(需要手动维护分区定义)。
- Laravel 不直接管理分区,需要你自行维护分区规则。
使用“表分区”代替“行分区”(更常见的归档方式)
另一种思路不是用数据库分区表,而是将旧数据移动到另一张表(如 logs_archive)。
做法:
- 主表:
logs(存放近期热数据,例如最近 3 个月)。 - 归档表:
logs_archive(结构与logs完全相同)。 - 调度任务:在 Laravel 的
schedule中定时执行:- 将
logs中 3 个月前的数据INSERT INTO logs_archive SELECT ... FROM logs WHERE ... DELETE FROM logs WHERE ...
- 将
优点:
- Laravel 完全支持两张表的管理(迁移、模型、查询)。
- 不需要数据库层次的分区支持(MySQL 5.6 以下或 SQLite 不支持分区)。
- 数据量可控时,操作灵活。
缺点:
- 删除旧数据时如果数据量很大,
DELETE会很慢且可能锁表。 - 需要处理两张表的联合查询(可以用视图或在模型中加
union)。
使用第三方包
有一些 Laravel 包可以帮你管理分区表:
- ongr-io/laravel-db-partition:支持按月/年自动创建分区。
- Mcamara/Laravel-MySQL 等。
但这类包通常较冷门,且可能不兼容最新 Laravel 版本。
选择建议
| 场景 | 推荐方案 |
|---|---|
| 数据量极大 (千万级),且需要极快地删除旧数据 | 使用 MySQL 原生分区表 + 手动维护迁移 |
| 数据量中等 (百万级),且希望用 Laravel 原生操作 | 使用 移动表归档(主表 + 归档表) |
| 需要有按月自动管理分区,且愿意引入依赖 | 使用 第三方包(如 ongr-io) |
| 业务查询需要频繁按时间过滤 | 分区表优势最明显 |
简单结论:
- 如果你需要“归档”只是把旧数据挪走,以便主表保持轻量,用第二方案(表分区/移动表) 更简单,Laravel 体验最好。
- 如果你需要“归档”在同一个表中高效按时间处理旧数据(例如按月删除、按时间查询),且数据量很大,用第一方案(分区表),但需要你手动写原生 SQL。
Laravel 默认的数据库迁移(Schema Builder)不支持定义分区,所以如果你选分区表,必须写 DB::statement() 来执行原生 SQL。