数据清洗应封装为独立可调用单元,推荐新建 app/Services/DataCleaner.php 类并注入 Database 和 Logger;避免硬编码在控制器中。

CodeIgniter 本身不提供“数据清洗”内置模块,它不是 ETL 工具或数据分析框架。数据清洗必须由开发者按业务规则手动实现——用模型查、用逻辑判、用事务删/改/填充,不能依赖 form_validation 或 cache 等现成组件。
数据清洗该放在哪里写?别塞进控制器或视图
把清洗逻辑硬编码在控制器里会导致:不可复用、无法测试、日志难追踪、分批处理易崩内存。正确做法是封装为独立可调用单元:
- ✅ Laravel 风格:写一个
app/Commands/CleanLegacyUsers.phpArtisan 命令(CI4 不原生支持,但可仿照实现 CLI 脚本) - ✅ CI4 推荐:新建
app/Services/DataCleaner.php类,注入Database和Logger,方法如removeInactiveUsersBefore($year) - ❌ 避免:在
UserController::store()里顺手$this->db->table('users')->where('created_at delete()—— 这属于副作用,且无回滚、无确认、无记录
清洗时怎么避免锁表或 OOM?分批 + 事务 + 日志缺一不可
遗留库动辄几万行,DELETE FROM users WHERE status = 'test' 一条执行可能卡死或超时。必须拆解:
- 用
limit+offset或基于主键范围分页,例如每次删 500 行:$this->db->limit(500)->delete('users', ['status' => 'test']) - 每批操作包在事务中:
$this->db->transStart(); ... $this->db->transComplete();,失败可整体回滚 - 每批完成后记录日志:
log_message('info', "Cleaned 500 test users (batch #{$i})"),便于中断后续跑 - 注意:CI4 的
transComplete()不自动重试,若需幂等,得自己加try/catch+ 计数器
验证类(form_validation)不能当清洗工具用
form_validation 是为「单次 HTTP 请求的输入校验」设计的,它的规则(如 required|valid_email)只作用于当前 $_POST,对已有数据库记录无效。试图用它做批量清洗会踩这些坑:
- 它不读数据库,
is_unique[users.email]只查当前提交值是否冲突,不帮你找出已存在的重复邮箱 - 没有批量返回机制,你不能用它一次性扫描全表并汇总「哪些邮箱格式非法」
- 错误信息设计为前端展示,不是结构化清洗报告;
validation_errors()返回字符串,没法直接喂给修复逻辑 - 若强行循环调用
set_data()+run()处理每条记录,性能极差,且绕过模型层,破坏数据一致性
清理后怎么确认效果?别只看 SQL 行数
删了 12,387 行不等于清洗完成。必须验证质量维度:
- 查残留:运行
SELECT COUNT(*) FROM users WHERE email NOT REGEXP '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$',确认正则清洗是否漏掉边缘 case - 比对关键字段空值率:
SELECT AVG(CASE WHEN phone IS NULL THEN 1 ELSE 0 END) AS null_rate FROM users,清洗前后对比 - 抽样人工核对:取清洗后的 100 条,检查姓名是否仍含 HTML 标签、时间字段是否全转为
Y-m-d H:i:s、状态码是否归一为active/inactive - 最易被忽略的是跨表一致性:比如删了
orders中的测试订单,但没同步删order_items,留下孤儿记录——这类必须用外键或显式 JOIN 核查


















