MySQL数据库的五大天坑!

73 阅读4分钟

本文首发于公众号:托尼学长,立个写 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数据库这五大天坑,兄弟们都记住了吗?