问题发现
在导入一个项目中的sql数据库文件时,出现一个mysql的错误提示,大致描述是:
Row size too large (> 8126),英文不算好的我看字面意思,估摸着大概就是说我们插入的行数据可能太大了,超过了设定的阙值;
一、问题导致的可能原因
这个限制主要是因为MySQL内部存储机制的约束,MySQL的InnoDB存储引擎有一个最大行大小限制关于mysql引擎内容比较多,这里我们只需要知道他是目前mysql 默认的存储引擎就好啦;
而这个最大行大小限制主要由于几个因素影响:
1、页大小
页是InnoDB管理数据的最小单位,InnoDB使用16KB的页来存储数据,行数据在进行保存插入的时候,要求我们的单行数据不能跨越多于半个页(8KB)。否则数据库会自动按照是否进行溢出页的机制来处理数据;
简单说的话,其实就是数据库中的每行数据我们可以看作是一所个人专属的小房子,里面预留了一个固定的空间给他们放东西,如果放入的东西太多了,超过这个空间大小,屋主就会考虑是否可以把东西放在屋外,来保障空间不至于太过拥挤,这里的房间内的空间就是页内空间大小,房外就是多出的
2、行格式
InnoDB支持几种行格式,如compact、redundant、dynamic和compressed。其中,dynamic和compressed格式是为了解决行大小限制而引入的,允许行中的某些列(如BLOB和TEXT类型)存储在页外。
这点简单的来说,四种行格式可以看作是房屋管理办法四个准则,每个准则都有各自适用的场景和优点;
关于行格式,我们这里只需要知道有哪几种,以及他们数据存储方式,各自应用场景即可;
2.1 compact格式
InnoDB的默认行格式,也是最常用常见的格式;采取的是位图压缩的存储方式;适用于大多数OLTP(在线事务处理应用场景。OLTP其实就是指那种较高并发,并且要求低延迟,专注业务操作的应用,类似银行交易、订单处理、库存更新那些情况比较常用。
2.2 Redundant格式
MySQL 5.0以前的默认行格式;适用具有大量NULL值的表;
2.3 Dynamic格式
从 MySQL 5.6.3 开始,默认的行格式是 DYNAMIC,Dynamic行格式具有高度的灵活性,可以动态地调整行的大小和存储方式。基于实际数据长度大小来进行调整存储空间,以节省存储空间;适用于包含大量长度可变列的表,例如包含TEXT、BLOB等大型字段的表。
2.4 Compressed格式
Compressed行格式采用压缩存储方式,它适用于存储大量重复数据或较大的表。Compressed行格式使用多种压缩算法,如Zlib和LZO等,能够显著减少磁盘I/O操作,提高存储和读取性能
3、BLOB和TEXT列
这点因素与上面那点有关,Blob 和 Text 是mysql中的大数据存储类型,但是在我们不设置行模式为ynamic和compressed的时候,这些列通常存储在页外,但它们的元数据(如长度)仍然存储在行内,而这个存储的大小跟行格式的设置会有所不同。也就是说明他会计入行大小限制的计算;
二、解决办法
好了,既然知道问题原因的可能了,现在就是开始如何解决了;
1、修改页大小(不推荐)
虽然mysql InnoDB的引擎默认的页大小是16KB,但是这个值并不是不能修改,修改配置文件;
添加或修改innodb_page_size参数来设置新的页大小。例如,innodb_page_size = 16384(以字节为单位,对应16KB),或者设置的更大;
不过需要注意的是:页大小的调整最好是在数据库初始化的初期去设置,一旦数据库初始化完成后,就不建议更改了,这种情况下意味着你原来已经存在的所有ibdata和ib_logfile文件都需要重建,那就不是很合适了,而且这样做也可能会带来一定的性能影响;
2、修改行格式
既然dynamic和compressed行格式就是为了解决行大小限制而引入的,我们可以修改该格式即可;当然了,我们也不是都要去修改这个,这个也是和我们的mysql版本有关的;
从 MySQL 5.6.3 开始,默认的行格式是 DYNAMIC,也就是说,其实在这个版本之后的我们其实就不需要修改行格式了;
不过如果你和博主一样是通过导入sql文件的方式创建的表的话,需要确认你的sql文件中是否有另外定义行格式;例如:
博主虽然数据库是8.0+,默认行模式已经是DYNAMIC,但是对方给的sql文件创建表的语句中指定了Compact行格式,这个原因大概率是因为它在导出时候环境是基于mysql5.x,而博主是8.0+的,所以这里导出的时候会有所出入;这里我讲所有的行模式设置都去掉了,默认就会按照DYNAMIC设置,就不会报错了;因此我们在做不同版本mysql的数据导入与导出时,需要特别小心版本不同带来的影响
3、修改数据类型为BLOB和TEXT列
如果你本来该字段就会需要存储较大的数据,就应该用blob和text来替换原来的数据类型VARCHAR或CHAR,这样能让数据大部分存储在溢出页中,而不去纳入大小限制的值计算;而如果我们之前设置了行模式的话,这个纳入计算的值占用会更小;
4、其他优化方式(可以参考使用)
4.1 合理设置数据类型大小
在进行表设计时候,一些列字段我们根据实际需要设计,例如varchar数据类型,如果实际存储值不大,长度就定义足够空间大小即可(即能用varchar64就不用varchar128,能用128就不要用256,尽可能合理分配空间);
4.2 合理进行表结构设计
如果设计表的时候,单表列尽量不要太多,适当的进行拆表将列分出去,也能在一定横渡上避免问题;
4.3 更换存储引擎
换另一种存储引擎,这个方法的话见仁见智,要根据自己的业务场景来抉择了,比如MyISAM引擎最大的缺点就是它不支持事务和高并发,所以才使得大多数情况下我们仍然在用InnoDB引擎的原因,虽然它读写性能上并没有前者优秀;