PHP项目数据清理如何制定过期规则

wen PHP项目 26

本文目录导读:

PHP项目数据清理如何制定过期规则

  1. 核心决策维度
  2. 过期规则的常见模式
  3. 实现过期规则的PHP方案
  4. 常见陷阱与最佳实践
  5. 综合示例:订单过期自动取消
  6. 制定规则时的业务确认清单

为PHP项目制定数据过期规则,通常需要结合业务逻辑存储成本合规要求性能来综合设计,以下是系统化的制定步骤和常见策略,附带PHP代码示例。


核心决策维度

  1. 数据性质

    • 临时数据(验证码、Session、URL令牌):通常几分钟到几天。
    • 日志数据(操作日志、访问日志):保留30天~1年。
    • 用户行为数据(购物车、浏览历史):保留7天~6个月。
    • 敏感数据(欧盟GDPR、中国《个人信息保护法》要求的数据):按法律要求的最小化保存时间。
  2. 可容忍的延迟

    • 实时删除(如支付倒计时到期的订单)→ 主动触发删除。
    • 批量清理(如日志归档)→ 定时任务(Cron)。
  3. 数据量级

    • 千万级以下:直接DELETE。
    • 亿级以上:考虑分区表(按时间分区,直接DROP分区)或TTL(Time To Live)索引(如MongoDB、ClickHouse)。

过期规则的常见模式

规则类型 适用场景 实现方式(PHP+MySQL)
固定时间淘汰 验证码、临时Token 存储created_at,查询时过滤 WHERE created_at < NOW() - INTERVAL 10 MINUTE,并定时清理
基于活动时间 用户session、在线状态 存储last_activity,超过N天未活动视为过期
基于状态+时间 订单(待付款24h未付自动取消) WHERE status='pending' AND created_at < NOW() - INTERVAL 24 HOUR
软删除+物理清理 回收站、历史记录 标记deleted_at,30天后物理删除
批量归档 10亿级日志 日期分区,定时 ALTER TABLE logs DROP PARTITION p20240101

实现过期规则的PHP方案

单条数据过期(实时查询+后台清理)

// 1. 查询时自动过滤过期数据(推荐用于业务逻辑)
public function getValidCode(string $phone): ?string
{
    $stmt = $pdo->prepare(
        "SELECT code FROM verification_codes 
         WHERE phone = :phone AND expired_at > NOW() 
         LIMIT 1"
    ); // expired_at 是预先计算好的绝对过期时间
    $stmt->execute(['phone' => $phone]);
    return $stmt->fetchColumn();
}
// 2. 定时任务清理(每天凌晨执行)
// 在 crontab 中设置:0 3 * * * php /path/to/cleanup.php
// cleanup.php
require 'bootstrap.php';
$pdo->exec("DELETE FROM verification_codes WHERE expired_at < NOW() - INTERVAL 1 DAY"); // 保留一天内的过期记录用于审计
echo "清理完成";

分区表策略(适合海量日志)

-- 建立按月分区表
CREATE TABLE access_logs (
    id BIGINT UNSIGNED AUTO_INCREMENT,
    user_id INT UNSIGNED,
    url VARCHAR(500),
    created_at DATETIME,
    PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (TO_DAYS(created_at)) (
    PARTITION p202501 VALUES LESS THAN (TO_DAYS('2025-02-01')),
    PARTITION p202502 VALUES LESS THAN (TO_DAYS('2025-03-01')),
    PARTITION p_future VALUES LESS THAN MAXVALUE
);
// PHP 定时任务:每个月1日删除6个月前的分区
$sixMonthsAgo = new DateTime('-6 months');
$partitionName = 'p' . $sixMonthsAgo->format('Ym');
$pdo->exec("ALTER TABLE access_logs DROP PARTITION {$partitionName}");
// 注意:需要先添加新分区,避免数据写入失败

基于TTL的数据库特性(最低成本)

  • MySQL 8.0+ 可结合 Event Scheduler + 存储过程,但通常建议用Cron。
  • Redis 原生支持TTL:PHP只用维护过期字段或利用Redis过期回调。
// Redis 验证码5分钟过期
$redis->setex("sms_code:{$phone}", 300, $code);
// 或利用MySQL 8.0的“不可见索引” + 定时任务,但不如Redis方便。

常见陷阱与最佳实践

  1. 不要依赖PHP进程内定时器
    用Cron(Linux)或任务调度系统(如Laravel Scheduler)替代 sleep() 循环,避免内存泄漏。

  2. 分批删除避免锁表
    对几百万行数据清理时,每次只删除1000行并短暂sleep。

    while (true) {
        $affected = $pdo->exec("DELETE FROM logs WHERE created_at < '2023-01-01' LIMIT 1000");
        if ($affected === 0) break;
        usleep(50000); // 50ms
    }
  3. 索引策略
    确保 expired_atcreated_atlast_activity 有索引,否则清理或查询会导致全表扫描。

  4. 容灾与回滚
    清理前备份或采用软删除。

    $pdo->beginTransaction();
    $pdo->exec("INSERT INTO logs_backup SELECT * FROM logs WHERE created_at < ...");
    $pdo->exec("DELETE FROM logs WHERE created_at < ...");
    $pdo->commit();
  5. 符合GDPR等法规
    如果数据标记为“可被遗忘”,需要提供物理删除接口,并在删除后断开业务关联。


综合示例:订单过期自动取消

// 规则:状态为pending(待支付)且 created_at 超过24小时 ⇒ 自动取消
// 实现方案:每次查询订单时,顺便检查并取消过期的,但更好的做法是定时任务
// 定时任务(每分钟执行一次)
$stmt = $pdo->prepare(
    "UPDATE orders 
     SET status = 'cancelled', cancelled_reason = 'payment_timeout' 
     WHERE status = 'pending' AND created_at < NOW() - INTERVAL 24 HOUR"
);
$stmt->execute();
echo "Cancelled {$stmt->rowCount()} orders.\n";

制定规则时的业务确认清单

  • [ ] 该数据最长可以保留多久?(法律、存储成本)
  • [ ] 如果提前删除,用户是否受影响?(例如购物车内容)
  • [ ] 过期后是否还需要统计用途?(需要保留脱敏或聚合数据)
  • [ ] 是否需要通知用户数据即将被清理?(例如GDPR要求的“数据销毁通知”)
  • [ ] 清理频率如何?实时 vs 批量?高峰期能不能执行?

场景 推荐规则 实现方式
验证码/临时令牌 固定时间(5~30分钟) Redis TTL / MySQL WHERE expired_at
用户Session 最后一次活动后1~7天 Laravel Redis Session + GC
操作日志 保留90天,物理删除 分区表 DROP PARTITION
软删除回收站 保留30天后物理删除 定时 DELETE LIMIT
敏感数据(GDPR) 按法规+用户请求立即删除 物理删除 + 备份清除

如果你能提供具体的业务场景(例如是电商订单、用户行为日志还是内容审核),我可以给出更精确的规则建议和SQL示例。

抱歉,评论功能暂时关闭!