【MySQL】行长度的一些限制

今天开发在导入数据的时候报一个错误:

Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs

原因:发现导入的数据单行长度较长。

官方文档的解决办法为:

1.垂直表字段拆分或者大字段合并(大字段最多不超过768,业务进行合并+拆分),divide your table into small ones. If one table contain more than 10 text colums, and the data contain is a little bit long. this error will be thrown out.

2.修改表的存储引擎,modify InnoDB to MyISAM.

3.修改row_format为COMPRESSED或者DYNAMIC,当然前提需保证innodb_file_format =Barracuda.

但为什么会出现上面的解释?

通过查询发现为innodb的一个限制:

我们知道innodb的页块大小默认为16kb,表中数据是存放在B-tree node的页块中,但如果表中一行的数据长度超过了16k,这时候就会出现行溢出,溢出的行是存放在另外的地方,存放该溢出数据的页叫uncompresse blob page。

innodb采用聚簇索引的方式把数据存放起来,即B+树结构,因此每个页块中至少有两行数据,否则就失去了B+树的意义(每一个页中只有一条数据,整个树成为了一条双向链表),这样就得出了一行数据的最大长度就限制为了8k。

当插入的一行数据不能在一个数据页块中存放时,为了保证该页至少能存放两行数据,innodb将会自动部分数据溢出到另外页中,一部分数据将存放在数据页块中,其大小为该列的前768字节,同时接着还有偏移指向溢出页。

如上面所说大字段的前768字节会存放在数据页块中,那么如果有10个大字段(如varchar(1000),text,blob同varchar同样存储前768字节),同样会超过一行数据8k的限制(10*768<8000,11*768>8000)。如果插入的值超过8000字节,则会报错(BLOB或TEXT同理):

测试如下:

表结构:

插入10列数据(10*768<8000)可以插入:

插入11列数据(11*768>8000)报错:

Text数据类型测试:

Blob数据类型测试:

明白了是怎么一回事后,就可以解决出现问题了,减少varchar(1000)的字段数量,或者改存储引擎为myisam;还可以增加page_size的大小:如改为32k,64k。由于需求不好改动,数据库的页块大小改变需要改动源码,了解该表以查询为主,更新非常少,所以改为myisam存储引擎:

可以看到myisam存储引擎不受此限制。

从上面也可以看出,在mysql innodb存储引擎表收到页块大小,数据以B+树的方式组织数据,导致单行数据不能超过8k,从而影响了表中大字段数据类型varchar,text,blob个数限制,在16k页块大小下,最好不要超过10个,在表设计中需要注意这个限制。

在innodb plugin的版本中,mysql引入了新的文件格式:barracuda,梭鱼;改文件格式中拥有两种新的行记录:compressed,dynamic,这两钟格式对于BLOB数据完全采用行溢出方式,在数据页中只占用20字节用于指向溢出页。

Antelope是innodb-base的文件格式, Barracude是innodb-plugin后引入的文件格式,同时Barracude也支持Antelope文件格式。两者区别在于:

文件格式

  1. Antelope(Innodb-base)

    支持行格式ROW_FORMAT=COMPACTROW_FORMAT=REDUNDANT特性 Compact和redumdant的区别在就是在于首部的存存内容区别。compact的存储格式为首部为一个非NULL的变长字段长度列表,redundant的存储格式为首部是一个字段长度偏移列表(每个字段占用的字节长度及其相应的位移)。在Antelope中对于变长字段,低于768字节的,不会进行overflow page存储,某些情况下会减少结果集IO.
  2. Barracuda(innodb-plugin)
    支持行格式ROW_FORMAT=DYNAMICROW_FORMAT=COMPRESSED特性这两者主要是功能上的区别功能上的。 另外在行里的变长字段和Antelope的区别是只存20个字节,其它的overflow page存储。另外这两都需要开启innodb\_file\_per\_table=1(这个特性对一些优化还是很有用的)

备注:

这里有一点需要注意,如果要使用压缩,一定需要先使用innodb_file_format =Barracuda格式,不然没作用。

参考:

InnoDB Row Storage and Row Formats

innodb中大字段的限制

Antelope 和Barracuda区别

时间: 2024-12-19 10:23:50

【MySQL】行长度的一些限制的相关文章

【MySQL】结构行长度的一些限制

今天被开发提交的DDL变更再次困惑,表中字段较多,希望将已有的两个varchar(4000)字段改为varchar(20000),我想innodb对varchar的存储不就是取前768字节记录当前行空间嘛,所以变更不会有任何问题的,但铁打的事实给了我结结实实的一个巴掌,直接报错,现在回放下这个错误! 模拟测试: CREATE TABLE `ttt` ( `id` DOUBLE , `select_type` VARCHAR (57), `table` VARCHAR (192), `type`

Mysql varchar长度问题

http://dinglin.iteye.com/blog/914276 http://www.cnblogs.com/fakis/archive/2011/03/07/1976532.html 如果某一项中设置的是varchar(50) 那么对英文当然是50 那么对中文呢 utf-8的中文占3个字节 那么,这个varchar(50)是不是只能存16个汉字了? 不是这样的,mysql低版本之前是这样的,但是5.0以后就不是了 mysql varchar(50)  不管中文 还是英文 都是存50个

mysql行锁和表锁

mysql innodb支持行锁和表锁,但是MyIsam只支持表锁.现在我们说说mysql innodb的行锁和 有如下表id为主键 为了出现演示效果,我们将mysql的autocommit设置为0 打开两个mysql命令行窗口,都设置为autocommit为0 窗口1: 窗口2: 这时候我们发现窗口2一直在阻塞,当我们在窗口1中commit后,发现窗口2有输出了. 上面我们更新不是同一个记录,为什么事物1没提交时,事物2一直等待了.因为这个时候用的是表锁. 现在我们给name字段加上索引,效果

mysql 行号 获取指定行数据

mysql 行号的实现 Select id,(@rowNum:[email protected]+1) as rowNo From first,(Select (@rowNum :=0) ) bOrder by first.id Desc 这样就可以实现mysql 的行号 获取指定行的数据可以使用limit 具体的使用如下: select * from first limit num,1 即可 mysql 行号 获取指定行数据,布布扣,bubuko.com

mysql sql长度限制解决

mysql sql长度限制解决 今天发现了一个错误: Could not execute JDBC batch update 最后发现原因是SQL语句长度大于1M,而我机器上的mysql是默认设置, 也就是说mysql通讯的数据包大小设置是1M,这就造成sql语句执行失败. 于是把mysql的配置文件(my.ini)中的max_allowed_packet = 6M变大, 问题就解决了.

MySQL 行转列 -》动态行转列 -》动态行转列带计算

Pivot Table Using MySQL - A Complete Guide | WebDevZoomhttp://webdevzoom.com/pivot-table-using-mysql/ Cross-Tabulation (Pivot Tables) with MySQL - CodeProjecthttps://www.codeproject.com/articles/363339/cross-tabulation-pivot-tables-with-mysql Pivot T

论JAVA实现MYSQL 行级锁(分布式锁实现方案一)

@Override @Transactional public String getCustomerId() { // return String.valueOf(getSequenceId(SEQ_CUSTOMER_ITEM_CODE.seqName)); String type=SEQ_CUSTOMER_ITEM_CODE.seqName; if (!sequenceValueMap.containsKey(type)) { SequenceDO sequenceDO = sequenceD

Mysql字段长度限制你真的了解吗?

一行中可以容纳多少字段长度?每个字段拥有长度又可以是多少?是否数据类型的限制长度固定不变?带着这几个问题,我们开始进行一系列研究. 一.行容纳的字段长度 众所周知,记录是以行的形式进行保存的,Mysql5.1以后,行的保存格式默认为Compact格式.行记录Compact格式为: 变长字段 NULL标志位 记录头信息 列1数据 列2数据 列3数据 ... 第一个变长字段是记录这行的总字段长度,如果行记录的字段总长小于255字节,变长字段就占一个字节(一个字节有8位,8位的二进制最多能表示到255

mysql 索引长度和区分度

首先  索引长度和区分度是相互矛盾的, 索引长度太短,那么区分度就很低,吧索引长度加长,区分度就高,但是索引也是要占内存的,所以我们需要找到一个平衡点: 那么这个平衡点怎么来定? 比如用户表有个字段 username ,要给他加索引,问题是索引长度多少合适? 其实我们知道 百家姓里面有百多个姓 ,但是大多数人的姓 集中在前十多个:如果我设置索引索引长度为1,对染占内存少,但是区分度低, 区分度低索引的效率越低.太长则占内存: 首先你要知道 mysql的索引都是排好序的.如果区分度高排序越快,区分