你是小阿巴,一台兢兢业业的服务器。
所有用户的请求都由你来处理,大家都夸你稳定可靠。
![]()
但自从公司引入了 MySQL 这个开源免费的关系型数据库后,一切都变了。
公司所有的业务数据都存在它那儿,用户的账号密码、发的帖子、买的东西,全都归它管。
大家天天夸它牛杯,老板甚至说:MySQL 数据库是公司的命根子!
![]()
你心里很是不爽:可恶的 MySQL,竟然敢抢俺的风头,给你点颜色瞧瞧!
于是某天深夜,程序员鱼皮加班困得迷迷糊糊,你趁机夺舍了他的意识,开始制定一个《MySQL 数据库毁灭计划》……
![]()
⭐️ 推荐观看视频版,动画更通俗易懂:https://bilibili.com/video/BV1iF6eBQEVM
打爆 MySQL! 第一招 - 连接攻击
你转了转脑子:想要操作 MySQL 数据库,得先和它建立连接,那俺就先从 连接 下手吧!
你翻看代码,发现这个狗鱼皮居然用了连接池,每次操作数据库都复用已有的连接。
![]()
你冷笑了声:哼,看俺把连接池给废了!
每次查询数据都新建一个 TCP 连接,用完立刻关闭。
![]()
这样一来,每次请求都要经历三次握手建立连接、用完再四次挥手关闭连接,耗时暴增!
![]()
而且 MySQL 默认最多只能接受 151 个连接,只要我建立连接够多够快,就能占满它的连接数名额,让 MySQL 拒绝新连接,直接返回错误!
你兴奋地想:哈哈,这下数据库要遭殃了~
![]()
等等,不对…… 频繁建立和关闭连接,好像也会让我自己的 CPU 爆炸?
不行不行,看来光搞连接还不够,俺要让数据库操作慢到极致!
第二招 - 批量改单条
你翻了翻代码,发现有个批量插入几十万条数据的逻辑,狗鱼皮居然用了批量插入语句,一条 SQL 插入多条数据。
![]()
你冷笑了声:哼,看俺把批量插入改掉,用 for 循环一条一条 INSERT 到数据库。
这样一来,每条 SQL 语句都要等网络传输来回一趟,这网络延迟可不是闹着玩的,时间全浪费在路上了。
你得意地笑了:嘿嘿,MySQL 你不是很快吗?这下你得陪俺耗到天荒地老了!
![]()
等等,不对…… 虽然 MySQL 被俺折腾得够呛,但俺自己也得一条一条发请求,也累得不轻啊。
第三招 - 就不走查询优化
你气得咬牙切齿:不行不行,前两招都是杀敌八百、自损一千,俺得再想一些能重创 MySQL 的狠招!
你翻了翻代码,发现狗鱼皮写的查询 SQL 语句竟然如此精妙:查询用户信息时只查了需要用到的几个字段,还精准添加了 WHERE 查询条件。
![]()
你冷笑了声:哼,就你会写 SQL?
看俺改成 SELECT * 查询所有字段,并且不加任何 WHERE 查询条件,把几千万行数据全部捞出来,你就慢慢查去吧哈哈哈哈哈哈哈。
![]()
但是这样查出来的数据就发生改变了,狗鱼皮肯定一眼就能发现。
![]()
我再看看……
诶,鱼皮竟然在 username、create_time、phone 这些字段上加了 索引,相当于给一本厚厚的书籍添加了目录,怪不得查询嘎嘎快。
![]()
嘿嘿,那我就让你的索引废掉!
俺在查询条件里给字段套个函数 WHERE YEAR(create_time) = 2026(原来是 WHERE createTime >= '2026-01-01'),这样 MySQL 就得把每一行的日期都先算一遍年份再比较,索引就会失效。
![]()
类似的思路,phone 字段是字符串类型,那俺偏偏传个数字 WHERE phone = 13800000000,MySQL 得偷偷把每一行都转换一遍,索引也会失效。
![]()
最妙的是,这种 SQL 功能上完全正确,表面看起来有索引、WHERE 条件也合理,不仔细看根本发现不了问题,上线后 MySQL 你就等着挨骂吧哈哈哈哈哈。
第四招 - 深分页问题
你面露凶光:不行,光这样还不够狠!平日鱼皮老狗待我不厚,俺还要埋个地雷,等着他踩上去。
数据库里有几千万条数据,鱼皮写了个分页查询商品列表的接口。
这狗居然知道用 游标查询,每次查询后记住上一页最后一条数据的 ID,下次查询时用 WHERE id > 上次的ID LIMIT 10 来查下一页。
由于 ID 是主键、自带索引,这种查询能直接命中索引,不用跳过大量数据,所以嘎嘎快。
![]()
你冷笑了声:哼,看俺把它改回普通的 LIMIT offset, size 分页方式。只要有用户不小心翻到很后面的页(比如第 100 万页),或者有爬虫疯狂翻页抓取数据,参数就会变成 LIMIT 10000000, 10。
![]()
看起来好像只取 10 条数据?
天真!MySQL 必须先费时费力扫描前 1000 万条,然后丢掉,再返回后面 10 条。够你数据库喝一壶的了~
![]()
第五招 - 事务锁
你转念一想:不过,这些慢查询很容易被慢查询日志和监控工具检测出来,鱼皮老狗肯定会发现。保险起见,还得想个更隐蔽的招数。
![]()
有了,MySQL 不是通过 事务 来保证数据的一致性么?
一组操作要么全部成功,要么全部失败。比如 A 给 B 转账,A 扣钱的同时 B 也会加钱,不会出现 A 扣了钱 B 却没收到钱的情况。
![]()
俺打算开一个大事务,一次性更新几千万条数据,然后俺不提交确认事务,就这么挂着,玩游戏去咯~
![]()
为了保证事务执行期间数据不被改乱,MySQL 会给数据上锁。俺的事务锁住了这几千万条数据后,只要不提交,这把锁就一直不会释放。如果其他请求也想改这些数据,就得排队等着,时间一长,等待的请求越来越多,全都卡在那儿,MySQL 你得背个大锅了。
![]()
不仅如此,这个大事务还会产生巨量的 Undo Log 回滚日志,把 MySQL 的内存也吃光,双重暴击!
![]()
还有个更轻松的方法,如果恰好有个正在被疯狂访问的表,我趁机执行 ALTER TABLE 语句来修改表结构。修改表结构时,MySQL 需要给这张表加一把元数据锁,确保没人能同时改它的结构。一旦遇到长事务还没提交,这个 DDL 就得排队等,而它一等,后面所有想访问这张表的请求全都被堵住!
![]()
哈哈,MySQL 你就卡着吧~ 还有护着 MySQL 的鱼皮老狗,头发掉光了也找不到原因。
第六招 - 删库跑路
想了这么多损招,还是难解你心头之恨。于是你产生了更变态的想法:前面俺都是让数据库变慢变卡,但都不致命,如果前面这些招数都被鱼皮化解了,那俺就不折磨它了,直接一条命令送走。
没错,就是数据库第一课学到的内容:从删库到跑路!
只要执行不加任何过滤条件的删除表数据 SQL —— DELETE FROM 用户表,就能删除所有用户。
![]()
或者执行更狠的删库 SQL —— DROP DATABASE,整个数据库直接没了,公司积累的所有业务数据,灰飞烟灭!
![]()
不过听说有些公司会在 MySQL 配置里开启 sql_safe_updates 安全开关,不带 WHERE 的删除会直接报错。还有的公司会定期备份数据,或者利用 binlog 日志来恢复数据……
![]()
哼,那就祈祷俺们这没做这些防护措施吧。
结局
你得意地看着这份完美的计划,并且把所有的代码改完:受死吧数据库,你千不该万不该和我小阿巴作对!
![]()
你的面相都变了,冷笑一声,按下了执行键……
很快,数据库的监控面板开始疯狂报警:连接数暴增、响应时间飙升、慢查询堆积如山、磁盘 I/O 爆表…… 短暂的挣扎过后,数据库抽抽两下,就彻底挂掉了。
![]()
你露出了宇智波狂笑:哈哈哈,MySQL 不过如此嘛!
![]()
但没过多久,你发现不对劲了。没有了 MySQL,用户登录不了、订单查不到、帖子全没了,业务彻底瘫痪,用户疯狂投诉。
最终业务黄了,公司倒闭,你也即将被销毁,这时的你才幡然醒悟:害人终害己啊!
![]()
点击下方关注鱼皮,获取免费编程学习路线、简历模板、面试题解、AI 知识库、项目教程、交流群。
一些对大家有用的资源:
100+ 编程学习路线 / 实战项目 / 求职指导
100+ 简历模板
300+ 企业面试题库 mianshiya.com
500+ AI 资源大全
1 对 1 模拟面试
动画学算法教程
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.