安全删除的核心是“删谁、删得准、删得留痕”,须先隔离待删数据建表确认,再人工抽查校验,最后执行删除或优先软删,严禁直接模糊匹配硬删。

不能直接用数据脱敏后执行删除——脱敏是掩盖,删除是移除,两者目的冲突,混用会导致误删或漏删。
SQL删除前必须先确认脱敏是否已完成且可逆
很多团队把“脱敏后删除”理解成“先跑一遍脱敏脚本,再跑一遍删除语句”,但实际中常出现脱敏逻辑有缺陷(比如只改了name没动id_card),或脱敏表和原表不是同一份快照。一旦脱敏出错,DELETE就再也无法回退。
- 脱敏操作本身应记录日志,包含影响行数、字段、时间戳,且保留原始备份表(如
user_orig_20240520) - 脱敏后的校验不能只看样例数据,要用
COUNT(*)对比关键字段非空值数量,例如:SELECT COUNT(*) FROM user WHERE id_card REGEXP '^[0-9]{17}[0-9Xx]$'; - 如果脱敏用了
UPDATE而非新建表,务必在删除前加SELECT ... FOR UPDATE锁表,防止中间写入
真正安全的删除流程:先隔离,再验证,最后删
敏感数据删除的核心不是“怎么删”,而是“删谁、删得准、删得留痕”。直接DELETE FROM user WHERE ...风险极高,尤其当条件涉及模糊匹配或关联子查询时。
- 第一步永远是
CREATE TABLE user_to_delete AS SELECT * FROM user WHERE [敏感条件],把待删数据单独拎出来 - 第二步人工抽查
user_to_delete里的phone、email等字段,确认无误后再执行DELETE - 如果业务允许,优先用
UPDATE user SET status = 'deleted', deleted_at = NOW() WHERE ...软删,比硬删更可控
WHERE条件里别信正则或LIKE匹配敏感字段
DELETE FROM log WHERE content LIKE '%身份证%'这类写法看似省事,实则极不可靠:可能漏掉已脱敏的变体(如id_card: ****1234),也可能误杀正常含“身份证”字样的业务日志。
- 真正可用的判断依据只能是结构化字段,比如
is_sensitive = 1、data_category IN ('PII', 'PCI') - 若必须依赖内容扫描,应先用
SELECT跑一遍,导出结果人工复核,再把ID列表转成IN (1,2,3...)精确删除 - MySQL 8.0+ 支持
REGEXP_LIKE(content, '[0-9]{17}[0-9Xx]'),但性能差、易误匹配,仅限小表临时用
最常被跳过的一步:删完立刻查information_schema.TABLES确认DATA_LENGTH是否明显下降;否则你以为删了10万行,其实只删了索引碎片。










