本文首发于公众号:托尼学长,立个写 1024 篇原创技术面试文章的flag,欢迎过来视察监督~
到了2025年,MySQL数据库最新版本出到了8.4,你以为它的各个功能已经足够成熟了吗?
下面我给兄弟们总结出来MySQL数据库的五大天坑,大家一定要谨慎避坑。
1、InnoDB 锁粒度失控
在InnoDB默认事务隔离级别可重复读(REPEATABLE READ)下,InnoDB 为解决幻读引入间隙锁,会锁定索引区间。
例如:
SELECT * FROM table1 WHERE id > 100 FOR UPDATE;
会锁定所有id > 100的已存在行 + 所有id > 100的间隙来避免幻读,这就意味着会阻塞id > 100区间的新行插入了,使MySQL的并发性急剧降低。
这也是很多互联网大厂将事务隔离级别改为读已提交的数据(READ COMMITTED)的最大原因。
2、InnoDB的IOPS默认设定过小
InnoDB中有个参数叫innodb_io_capacity,用于定义 InnoDB 后台任务(比如从 Buffer Pool刷新数据页、合并Change Buffer中的数据)可使用的 每秒 IO 操作数,也就是我们常说的IOPS。
你知道在MySQL中给它的默认值是多少吗?
200,你没听错,在SSD磁盘的时代默认值只给200,我们可以根据服务器磁盘和自身业务情况,将该值调整为5000到20000,甚至更高。
3、MySQL的VARCHAR长度
对于MySQL VARCHAR的定义是,存储长度可变的字符串,括号内的数字表示最大存储长度。
例如,VARCHAR(50)表示该字段可以存储最多50个字符的字符串,而VARCHAR(500)则可以存储最多 500 个字符。
虽然VARCHAR类型在定义时指定了最大长度,但实际上它只存储实际输入的字符数量。
这意味着无论定义为VARCHAR(50)还是VARCHAR(500),如果实际存储的字符串长度相同,它们所占用的存储空间是相同的。
很多同学觉得既然如此,那我就把VARCHAR通通往大了设置呗,反正也不会影响啥,还能以备不时之需,那你就被MySQL给坑了。
MySQL 在执行排序、分组、JOIN 等操作时,VARCHAR 会转换为 CHAR,转换后的 CHAR 的长度就是 VARCHAR 的长度,在内存中所占用的空间就变大了。
也就是说,对 VARCHAR(1000) 的字段进行排序,若实际仅存储10个字符的话,那99%的内存空间就被浪费掉了。
而一旦内存临时表的内存空间不足,就会变成磁盘临时表,排序耗时就会从毫秒级变成秒级,大幅降低排序性能。
4、InnoDB Buffer Pool默认设定过小
InnoDB Buffer Pool是 MySQL 性能的核心,它将磁盘上的表数据、索引数据缓存到内存,避免频繁磁盘 IO,Buffer Pool越大性能就越好,我们可以将其理解为MySQL中的HashMap。
有个参数innodb_buffer_pool_size是用来设置 Buffer Pool大小的,默认值仅为128M。
这就意味着如果不更改该参数,你的数据库服务器的内存有64G的话,Buffer Pool仅仅用到了一个零头中的零头,相当于在满汉全席中只吃咸菜。
强烈建议将其设置为服务器内存的70%到80%,真的不是默认的就是最合理的。
5、InnoDB Buffer Pool 命中率暴跌
InnoDB Buffer Pool在正常情况下缓存命中率是≥99%的。
但InnoDB Buffer Pool的LRU淘汰算法存在设计缺陷,它的LRU 算法的冷热分区设计,仅能抵御少量、零散的冷数据访问。
但无法应对海量数据大表的全表扫描这种 “大规模、一次性” 的操作,会把大量冷数据加载到Buffer Pool,挤出核心热点数据,直接引发缓存命中率暴跌、磁盘IO 飙升、查询性能断崖式下降,甚至在高并发场景下会导致数据库被打挂。
这种情况下,我们一定要规避在业务的高峰期,对生产环境数据库的海量数据大表进行全表扫描,必须扫描的场景要限定在凌晨低峰期进行。
MySQL数据库这五大天坑,兄弟们都记住了吗?