数据库无关联设计,删除数据

一、为什么不直接物理删除

即使业务上"不需要保留"订单数据,直接 DELETE 仍会带来问题:

场景:某电商决定只保留3个月订单,过期删除

直接 DELETE 的问题:

问题 说明 实际影响
主从延迟 大删除产生大量 binlog 从库延迟几分钟到几十分钟
锁竞争 DELETE 期间锁住大量行 影响正常读写,可能超时
磁盘碎片 删除后空间不释放,只是标记可复用 表文件大小不变,浪费空间
无法恢复 误删后只能从备份恢复 恢复时间几小时到几天
事务日志膨胀 undo log 记录删除操作 可能撑爆磁盘
缓存穿透 大量删除导致 Buffer Pool 污染 影响后续查询性能

二、标准做法:多阶段生命周期

完整的数据流转路径

订单创建 → 热数据(3个月) → 温数据(1年) → 冷数据(3年) → 归档/删除
   ↓            ↓                ↓               ↓              ↓
在线库      在线库          历史库          冷存储        合规销毁
可读写      可读写          只读查询        离线查询       物理删除

实际表设计:状态字段

# orders 表增加状态字段
orders 表字段:
- id
- user_id
- user_name
- total_amount
- status          # 业务状态:待支付/已完成/已取消
- data_status     # 数据生命周期状态:热/温/冷/已归档
- created_at
- archived_at     # 归档时间
- deleted_at      # 标记删除时间

数据状态流转示例:

订单ID 创建时间 data_status deleted_at 说明
1001 2024-11-01 热 NULL 3个月内,在线库可读写
1002 2024-08-15 温 NULL 3-12个月,在线库只读
1003 2023-06-01 冷 NULL 1-3年,已迁移到历史库
1004 2022-01-01 已归档 2025-01-01 超过3年,已归档并标记删除

三、不同场景的处理策略

场景1:订单数据完全不需保留(如测试数据、临时购物车)

策略:定时任务批量删除 + 软标记

# 每天凌晨执行
def cleanup_temp_carts():
    # 步骤1:标记(软删除)
    db.execute("""
        UPDATE shopping_carts 
        SET status = '已删除', 
            deleted_at = NOW()
        WHERE status = '临时' 
        AND created_at < DATE_SUB(NOW(), INTERVAL 7 DAY)
        LIMIT 10000
    """)
    
    # 步骤2:延迟物理删除(可选,7天后真正删除)
    db.execute("""
        DELETE FROM shopping_carts 
        WHERE status = '已删除' 
        AND deleted_at < DATE_SUB(NOW(), INTERVAL 7 DAY)
        LIMIT 5000
    """)

数据状态:

id user_id status created_at deleted_at
1 100 正常 2024-02-10 NULL
2 101 已删除 2024-02-01 2024-02-05
3 102 已删除 2024-01-20 2024-01-25

场景2:订单数据需要保留但不可见(用户注销场景)

策略:更新状态 + 数据脱敏

# 用户注销时
def anonymize_user_orders(user_id):
    # 不删除,只脱敏和标记
    db.execute("""
        UPDATE orders 
        SET user_name = '[已注销]',
            user_phone = NULL,
            user_address = NULL,
            is_visible = 0,        # 前端不可见
            data_status = '已脱敏'
        WHERE user_id = ?
    """, user_id)

订单数据变化:

id user_id user_name total_amount is_visible data_status
1001 3 王五 1299.00 1 正常
1002 3 [已注销] 599.00 0 已脱敏

效果:

  • 后台对账、财务审计仍能看到完整数据
  • 前端不展示给用户
  • 满足合规要求(如 GDPR 的"被遗忘权")

场景3:订单数据需要归档清理(节省在线库空间)

策略:分区表 + 在线 DDL 删除分区

MySQL 分区表示例:

-- 按月分区
CREATE TABLE orders (
    id BIGINT,
    created_at DATETIME,
    ...
) PARTITION BY RANGE (YEAR(created_at) * 100 + MONTH(created_at)) (
    PARTITION p202401 VALUES LESS THAN (202402),
    PARTITION p202402 VALUES LESS THAN (202403),
    PARTITION p202403 VALUES LESS THAN (202404),
    ...
);

删除过期数据:

-- 直接删除整个分区(毫秒级完成,不产生大量 binlog)
ALTER TABLE orders DROP PARTITION p202301;
ALTER TABLE orders DROP PARTITION p202302;
ALTER TABLE orders DROP PARTITION p202303;

数据流转:

  1. 热数据:最近3个月分区,在线库可读写
  2. 温数据:3-12个月分区,在线库只读查询
  3. 冷数据:1年前分区,迁移到历史库后删除原分区

场景4:订单数据需要彻底物理删除(合规要求)

策略:专用清理任务 + DBA 审批

# 合规删除流程
def compliant_delete():
    # 1. 标记待删除
    db.execute("""
        UPDATE orders 
        SET delete_flag = 1,
            delete_request_time = NOW(),
            delete_reason = '用户主动删除'
        WHERE user_id = ? 
        AND status = '已完成'
        AND created_at < DATE_SUB(NOW(), INTERVAL 3 YEAR)
    """)
    
    # 2. 进入审批队列(等待 DBA 审核)
    create_approval_task(user_id, "合规删除申请")
    
    # 3. 审批通过后,执行物理删除(低峰期)
    # 先备份,再删除
    export_to_archive(user_id)  # 先归档到冷存储
    db.execute("DELETE FROM orders WHERE delete_flag = 1")

四、决策树:何时物理删除 vs 标记删除

是否需要物理删除?
    │
    ├─ 有合规要求(GDPR、金融法规)
    │   └─ 是 → 物理删除(但先归档备份)
    │
    ├─ 数据量极大,影响性能
    │   └─ 是 → 分区表,直接 DROP PARTITION
    │
    ├─ 数据可恢复要求高
    │   └─ 是 → 标记删除,永不物理删除
    │
    ├─ 成本考虑(存储费用高)
    │   └─ 是 → 迁移到廉价冷存储后物理删除
    │
    └─ 默认策略
        └─ 标记删除 + 延迟清理(7-30天后物理删除)

五、实际案例对比

案例A:淘宝订单

  • 策略:永不物理删除
  • 方式:状态字段 + 分区表
  • 原因:交易凭证,可能需要追溯10年
订单状态 数据状态 用户可见 后台可见
已完成 热数据 是 是
已删除(用户侧) 冷数据 否 是(运营可查)
已归档 归档库 否 是(需申请)

案例B:临时购物车

  • 策略:7天后物理删除
  • 方式:定时任务批量删除
  • 原因:无保留价值,节省空间
创建时间 操作 数据状态
0-7天 正常使用 在线库
7-14天 标记"已过期" 在线库(不可见)
14天后 物理删除 已删除

案例C:用户聊天记录

  • 策略:软删除 + 定期归档
  • 方式:状态字段 + 历史库
  • 原因:可能恢复,合规要求
时间 状态 存储位置
删除时 标记"已删除" 在线库
30天后 迁移 历史库
1年后 压缩归档 冷存储
3年后 物理删除 无

六、总结

数据重要性 推荐策略 方式
核心交易数据 永不删除 状态字段 + 分区 + 归档
用户主动删除 软删除 状态字段 + 脱敏
临时数据 延迟物理删除 定时任务 + 分批
日志/监控数据 定期清理 按时间分区删除
合规要求删除 物理删除 审批流程 + 备份先行

核心原则:

  1. 默认软删除:用状态字段标记,保留恢复可能
  2. 物理删除是最后手段:只有明确合规要求或成本压力才执行
  3. 分批操作:任何删除都要限流、分批,避免影响业务
  4. 先备份后删除:物理删除前务必归档备份
  5. 分区表优先:按时间分区,删除分区比 DELETE 高效百倍

即使"不需要保留"的订单数据,大公司也会先标记删除,观察一段时间(如30天),确认无问题后再分批物理删除。这是对数据安全的敬畏。

posted @ 2026-04-06 16:33  爱晒太阳的懒猫。。  阅读(60)  评论(0)    收藏  举报