codeigniter 3需手动实现分表归档,核心是复用分表逻辑但将后缀改为“archive_年月”,动态设置$table为归档表名,分批迁移数据并自动路由查询;建表须显式指定引擎与字符集,归档表应禁用写权限并纳入备份。

CodeIgniter 本身不提供数据归档功能,必须靠手动分表 + 定时迁移 + 查询路由三者配合实现;直接 DELETE 或 UPDATE 大量历史记录会锁表、拖慢线上业务,这不是归档,是自毁。
如何用分表模拟归档表(如 b_log_archive_202512)
归档本质是把「低频访问但需保留」的数据移到独立物理表中,不是删掉。在 CodeIgniter 3 中,最稳妥的方式是复用分表逻辑,但把后缀含义从「按月写入」改为「按年归档」:
-
$this->table动态设为b_log_archive_202512,而非b_log_202512,避免和在线表混淆 - 建表语句必须显式指定
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4,否则 CI 3 的db->list_fields()无法还原索引和默认值,导致created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP丢失 - 归档表建议禁用写入权限(MySQL 层面
REVOKE INSERT,UPDATE ON db.b_log_archive_* FROM 'app_user'@'%'),只留 SELECT,防误操作
怎么把老数据安全迁移到归档表(不锁主表)
不能用 INSERT INTO b_log_archive_202512 SELECT * FROM b_log WHERE created_at 一把梭——这会锁住 <code>b_log 几分钟甚至更久。要分批迁移:
- 用
WHERE id BETWEEN ? AND ?分页,每次搬 5000 行,查完立刻COMMIT - 迁移脚本必须加事务,并在每批后
sleep(0.1),避免 CPU 和 I/O 打满 - 删除原表数据前,先
SELECT COUNT(*)核对归档表行数,再执行DELETE FROM b_log WHERE id IN (…),别用WHERE created_at ,防止时间字段有 NULL 或时区偏差
查询时如何自动路由到归档表或在线表
用户查「最近 3 个月日志」应走 b_log,查「2025 年全年」就得跨 b_log 和 b_log_archive_2025*。不能靠前端拼 SQL,得封装方法:
- 在模型里写
getByTimeRange($start, $end),内部判断时间范围,自动调用不同表的get(),再array_merge()结果 - 跨表分页不能用 CI 的
limit(),得先查总条数(UNION ALL SELECT COUNT(*) FROM …),再按 offset 手动切片 - 如果归档表加了
archive_flag TINYINT DEFAULT 1字段,就别在查询条件里写它——归档表本就不该有非归档数据,加这个字段纯属冗余且干扰优化器
最容易被忽略的是权限与备份策略:归档表虽不常写,但必须纳入每日全量备份;MySQL 用户若只有 SELECT 权限,mysqldump 就会跳过这些表,线上恢复时才发现归档数据丢了。











