zoukankan      html  css  js  c++  java
  • 【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同理):

    测试如下:

    表结构:

    屏幕快照 2015-12-10 上午10.36.54.png

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

    屏幕快照 2015-12-10 上午10.44.24.png

    屏幕快照 2015-12-10 上午10.44.39.png

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

    屏幕快照 2015-12-10 上午10.45.31.png

    Text数据类型测试:

    屏幕快照 2015-12-10 上午10.52.33.png

    屏幕快照 2015-12-10 上午10.54.04.png

    Blob数据类型测试:

    屏幕快照 2015-12-10 上午10.52.25.png

    屏幕快照 2015-12-10 上午10.54.42.png

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

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

    屏幕快照 2015-12-10 下午8.48.04.png

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

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

    屏幕快照 2015-12-10 上午11.38.52.png

    屏幕快照 2015-12-10 上午11.12.39.png

    屏幕快照 2015-12-10 上午11.23.37.png

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

    文件格式

    1. Antelope(Innodb-base)

      支持行格式
      ROW_FORMAT=COMPACT
      ROW_FORMAT=REDUNDANT
      特性 
      Compact和redumdant的区别在就是在于首部的存存内容区别。
      compact的存储格式为首部为一个非NULL的变长字段长度列表,redundant的存储格式为首部是一个字段长度偏移列表(每个字段占用的字节长度及其相应的位移)。在Antelope中对于变长字段,低于768字节的,不会进行overflow page存储,某些情况下会减少结果集IO.
    2. Barracuda(innodb-plugin)

      支持行格式
      ROW_FORMAT=DYNAMIC
      ROW_FORMAT=COMPRESSED
      特性
      这两者主要是功能上的区别功能上的。 另外在行里的变长字段和Antelope的区别是只存20个字节,其它的overflow page存储。另外这两都需要开启innodb\_file\_per\_table=1(这个特性对一些优化还是很有用的)

    innodb 一般对应 Compact  ,MyISAM 一般对应静态与动态

          mysql中若一张表里面存在varchar、text以及其变形、blob以及其变形的字段的话,那么这个表其实也叫动态表,即该表的 row_format是dynamic,就是说每条记录所占用的字节是动态的。其优点节省空间,缺点增加读取的时间开销。反之,这张表叫静态表,该表 row_format为fixed,即每条记录占用字节一样。优点读取快,缺点浪费部分空间,所以,做搜索查询量大的表一般都以空间来换取时间,设计成静态表。

    修改行格式

    ALTER TABLE table_name ROW_FORMAT = DEFAULT

    修改过程导致:

    fixed--->dynamic: 这会导致CHAR变成VARCHAR

    dynamic--->fixed: 这会导致VARCHAR变成CHAR

    备注:

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

    参考:

    InnoDB Row Storage and Row Formats

    innodb中大字段的限制

    Antelope 和Barracuda区别

  • 相关阅读:
    如何用php启动exe程序,并在进程中查看?
    如何用原生js或jquery设置select的值
    php5 升级 php7 版本遇到的问题处理方法总结
    phpexcel 读取日期的问题?
    PHPExcel_Reader_Exception: is not recognised as an OLE file in Classes问题解决方法
    QT Unexpected CDB exit 问题的解决办法
    html调用摄像头的方法汇总
    win7 32位 安装opencv-python后,运行时提示 "from .cv2 import *: DLL load failed: 找不到指定的模块" 的解决办法
    centos7 crontab 定时执行python任务不执行的原因及解决办法
    centos 7 生成文件名乱码的问题如何解决?
  • 原文地址:https://www.cnblogs.com/zhiqian-ali/p/5037317.html
Copyright © 2011-2022 走看看