刚接手一个老项目时,修改我被一条update语句坑惨了。数据那条SQL把订单表里所有用户的修改余额都增加了100元——因为漏写了where条件。业务方发现时,数据多发的修改钱已经追不回来了。
修改数据库的数据SQL,本质就三件事:改结构、修改改数据、数据改权限。修改但每一件都藏着细节。数据
先说改数据,修改这是数据最日常的操作。INSERT、修改UPDATE、数据DELETE,修改语法简单到看一眼就会。但真正考验人的是写条件。我见过太多人写update时,先select确认一遍,再改,改完再select一遍——这习惯很好,但还不够。更稳的做法是,先在事务里执行,检查影响行数,确认无误再commit。别小看这个动作,生产环境里一条没带条件的delete,足以让你半夜爬起来加班。
改结构就麻烦些。ALTER TABLE能加字段、改类型、删约束,但执行时往往锁表。有一次我在业务高峰期给一张千万级的表加索引,结果直接堵死了所有查询。后来学乖了,用pt-online-schema-change这类工具,或者干脆挑凌晨操作。还有个容易忽略的点:修改字段类型时,MySQL会隐式转换,可能把字符串'123abc'变成123,数据就悄悄变了。这种坑,光看执行计划是看不出来的。
权限修改是DBA的活,但开发也得懂。GRANT和REVOKE不复杂,麻烦的是最小权限原则。我见过测试环境里给开发账号开了ALL PRIVILEGES,结果误删了整张表——虽然能恢复,但流程走下来,半天时间就没了。现在我都习惯只给SELECT、INSERT、UPDATE、DELETE,连DROP都收着。
说个真实案例。上个月我同事要清理一批无效用户,写了个DELETE语句,条件里用了一个关联子查询。跑之前他自信满满,说影响行数只有2000多。结果执行完才发现,子查询里有个NULL值,导致匹配到了全表——3万条记录全没了。幸亏有备份,但恢复数据花了两小时。后来我们规定,任何DELETE和UPDATE,必须先用相同条件跑SELECT,把结果集导出来人工确认一遍。麻烦是麻烦,但值得。
有个细节很多人不知道:修改数据时,尽量用主键或唯一索引作为条件。不是所有字段都能走索引,比如在性别字段上过滤,如果表里就两种值,索引基本没用,全表扫描是必然的。这时候如果表很大,你的UPDATE会拖垮整个库。所以写SQL前,EXPLAIN一下,看看是不是全表扫描,如果走了filesort或者临时表,就得想想别的办法。
还有个容易踩的坑:字符集和排序规则。两个表join时,如果一个是utf8mb4,一个是utf8,MySQL会做隐式转换,导致索引失效。这问题在修改字段时特别常见——你只改了类型,没注意字符集,结果性能直接崩了。我处理过一次,线上慢查询日志里全是这种语句,排查了半天才发现是两个表的collation不一致。
最后说点主观的。很多开发觉得SQL修改是小事,随手就写,随手就执行。但数据库这东西,一旦数据错了,恢复成本极高。我自己的习惯是:任何修改操作,先备份,再执行,执行完立刻验证。备份不一定要dump整个库,但至少把要改的数据导出来。别嫌麻烦,真出事的时候,你会感谢自己多花的那两分钟。
写SQL改数据,技术含量不在语法,而在对数据的敬畏。你永远不知道一条简单的语句,会在什么场景下捅出多大的娄子。所以,谨慎点,再谨慎点,准没错。