晚上十点,办公室就剩老张一个人。他盯着屏幕,手边的咖啡早就凉了。又是一次批量导入失败,报错信息里写着:‘Duplicate entry for key PRIMARY’。他叹了口气,这已经是本周第三次卡在‘入库’这一步了。
入库不是复制粘贴
很多人觉得,把数据从一个地方搬到数据库,不就是个‘放进去’的事儿?其实没那么简单。比如监控系统每秒生成上千条访问日志,如果一条条插,数据库早就扛不住。这时候得用批量提交,但批量也不是越大越好。试过一次性塞五万条?内存直接爆掉,服务挂了半小时。
老张后来改成了分段处理,每次两千条,中间加个短暂休眠。既不会压垮服务器,又能保证速度。代码改成这样:
for i in range(0, len(logs), 2000):
batch = logs[i:i+2000]
db.execute_batch(insert_sql, batch)
time.sleep(0.1) # 给系统喘口气
数据格式对不上,入库就翻车
上周新上了个API接口,返回的时间戳带毫秒,而数据库字段只支持到秒。结果一入库,全报‘Data truncation’。开发那边说‘前端显示不需要毫秒’,可数据进不来,后端报表全空着。
最后是运维小李动手,在入库前加了一层清洗:
def clean_timestamp(ts):
return ts.split('.')[0] # 去掉毫秒部分
logs_clean = [dict(log, timestamp=clean_timestamp(log['timestamp'])) for log in raw_logs]
就这么几行,救了当天的日报。
别等凌晨才发现数据丢了
有次升级脚本,忘了关定时任务,两个进程同时读同一份日志文件,结果一半数据重复入库,另一半被跳过。第二天查问题,发现某些IP的访问记录凭空多出三倍。这种问题白天看不出来,等到业务部门对账才发现不对劲。
现在他们加了文件标记机制:处理完的日志会重命名,加上‘_imported’后缀。再配合简单的数据库去重查询,基本杜绝了这类事故。
入库这事儿,看着不起眼,真出问题都是大事。它不像重启服务器那么干脆,更像是每天早晚的打卡,做对了没人注意,漏一次,全盘皆输。