TP6.0无内置数据归档功能,需应用层控制+数据库配合实现;冷热分离须依赖时间字段索引优化,避免全表扫描引发锁表。
ThinkPHP 6.0 本身不提供自动归档、冷热分离或表分区能力——它只是 ORM 和请求调度层,底层归档逻辑得靠你自己设计。别指望 Db::archive() 或 $model->moveToArchive() 这类方法存在,它们不存在。
真正能落地的归档,是「应用层控制 + 数据库配合」:先用 TP6 查询出待归档数据,再通过原生 SQL 或事务批量搬移,最后清理源表。关键不是 TP6 能做什么,而是你如何用它安全地触发和管控这个过程。
典型场景是订单、日志、操作记录等按 create_time 划分冷热。TP6 查询时必须避免全表扫描,否则归档脚本一跑就锁表、拖垮线上服务。
create_time 字段有索引(单列或联合索引,如 (status, create_time))where('create_time', ',别用 <code>whereYear('create_time', ' —— 后者无法命中索引
chunk() 分批处理要配 limit 和 order:否则可能漏数据或重复归档示例(安全分页归档):
$date = '2024-01-01';$model->where('create_time', '<=', $date) ->where('status', 1) // 加业务状态过滤,缩小范围 ->order('id ASC') // 必须有序,避免 chunk 跳过/重复 ->chunk(1000, function ($items) use ($archiveModel) { $archiveModel->insertAll($items->toArray()); $items->each(function ($item) use ($model) { $model->where('id', $item['id'])->delete(); }); });
TP6 完全不处理表分区逻辑,分区是数据库层面的事。你得手动用 MySQL 命令建分区表,再让 TP6 的模型指向它(比如把 orders_2023 当成独立模型),而不是指望 TP6 自动生成分区。
常见错误:
table('orders PARTITION (p2023)') —— 无效,PDO 不支持 PARTITION 语法直写Db::execute() 执行 ALTER TABLE orders REORGANIZE PARTITION... 但没加事务和锁检查,导致主从延迟或阻塞写入datetime 但没转成 UNIX_TIMESTAMP,MySQL 分区要求表达式必须是 deterministic正确做法:分区建好后,在 TP6 中用不同模型分别操作当前表与历史表,例如:
// 归档时写入appmodelarchiveOrders2023::create($data);<p>// 查询时按需切换if ($year < 2024) {$list = appmodelarchiveOrders2023::where(...)->select();} else {$list = appmodelOrders::where(...)->select();}
归档不是一次性的开发任务,而是长期运行的运维动作。TP6 写的命令行脚本(php think archive:orders)最容易出问题的地方不在逻辑,而在边界控制。
sleep(0.1) 或 usleep(50000) 控制吞吐,避免瞬间打爆 I/OSELECT COUNT(*) FROM orders WHERE create_time <= ? AND archived = 0,用 archived 字段标记是否已归档,防止重跑Db::raw('NOW() - INTERVAL 12 MONTH')
最常被忽略的一点:归档后的 ANALYZE TABLE 和 OPTIMIZE TABLE 不该由 TP6 触发——那是 DBA 的事,脚本里只负责通知或写日志。