SQL错误导致生产数据全表更新

19 阅读2分钟

背景

系统迭代更新,会有业务数据需要变更,最近我们遇到了一件棘手的生产事件,开发同事本来要更新表中的很少一部分数据,但是由于UPDATE SQL编写问题,将整个表的一个字段进行了更新。SQL大概这个样子

sql
UPDATE t_gcl_store t 
SET t.authorization_state = '2' AND t.store_no =00d74859bb1945ffbfbfc7d05f5b3893'

原因

使用了 AND:在 SQL 中,SET 子句的语法需要用逗号 , 来分隔多个赋值,而不是用 AND。当你用 AND 时,MySQL 会尝试计算 t.authorization_state = '2' AND t.store_no = '00d74859bb1945ffbfbfc7d05f5b3893' 的结果。这里的结果是布尔值(TRUE 或 FALSE),在 MySQL 中,TRUE 被视为 1,FALSE 被视为 0。

赋值逻辑: 由于你在 SET 子句中使用了 AND,MySQL 实际上将 t.authorization_state 设置为这个布尔表达式的结果:

如果 t.store_no 等于 00d74859bb1945ffbfbfc7d05f5b3893,表达式结果为 TRUE,t.authorization_state 会被更新为 1(TRUE)。 如果不等于,结果为 FALSE,而 t.authorization_state 会被更新为 0(FALSE)。 全表更新: 如果没有 WHERE 子句,MySQL 会对表中的每一行执行这个更新,导致所有行的 authorization_state 都被更新为 0 或 1(具体取决于 store_no 的值)。

解决方案

要正确更新多个列,你应该使用逗号 , 来分隔列的赋值,并加入一个 WHERE 子句来指定条件,例如:

sql UPDATE t_gcl_store t SET t.authorization_state = '2', t.store_no = '00d74859bb1945ffbfbfc7d05f5b3893' WHERE <条件>; -- 请在这里加上合适的条件,例如 t.store_no = '某个值' 这样可以确保你只更新符合条件的记录,而不是全表。

导出sql执行日志

DBA利用阿里第三方工具导出啦一份sql执行日志

image.png

SQL整理分析

因为是店铺授权表-所以更新失败,导致用户的一些其他操作也有问题,所以把一段时间内的sql执行日志都导出啦,分析哪些有问题,不幸中的万幸,只有全表更新的sql有问题,把表状态的更新回滚即可

总结

数据脚本变更一定要重视,在重视,避免的方案很多,添加复核人,在测试库执行假数据-测试你的脚本是否有问题,还可以把生产的一条数据导出来,插入测试库或者开发库验证你的脚本