MySQL表列数和行大小限制

Posted 蚂蚁小哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL表列数和行大小限制相关的知识,希望对你有一定的参考价值。

一:引言

  1118 - Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
  翻译:1118 -行太大。所用表类型的最大行大小(不包括BLOBs)是65535。这包括存储开销,请查看手册。您必须将一些列更改为TEXT类型或BLOBs类型

  这个错误我相信大家都遇到过,当数据库里面的字段特别多且每个字段占的存在范围字节也特别大就会有可能出现当前错误,主要原因是行大小超过了65535个字节

二:列数限制

MySQL的每个表有4096列的硬限制,但给定表的有效最大值可能更少。确切的列限制取决于几个因素:
    ①:表的最大行大小约束列的数量(可能还有大小),因为所有列的总长度不能超过此大小。
        
    ②:各个列的存储要求限制了给定最大行大小内的列数。某些数据类型的存储要求取决于存储引擎、存储格式和字符集等因素。
    ③:存储引擎可能会施加限制表列计数的其他限制。例如InnoDB每个表的限制为1017列。

二:行大小限制

①:MySQL表具有65535字节的最大行大小限制,即使存储引擎能够支持更大的行也是如此。
在MySQL的设定中单行数据最大能存储65535byte的数据(注意是byte,而不是字符)。 ②:对于默认的16KB InnoDB页大小,最大行大小略小于8KB 。对于64KB页,最大行大小略小于16KB。
如果包含可变长度列(例如:text)的InnoDB行超过最大行大小,InnoDB选择可变长度列进行页外存储。

1:基本说明及错误演示

字符集所占长度:
    latin1字符集:        一个字母占一字节
    gbk字符集:           一个汉字占二字节
    utf8(utf8mb3):     一个汉字占三字节
    utf8mb4:            一个汉字占四字节(可存储emoji表情)


在刚接触MySQL的人设计表时可能出现此方式的创建表:
    CREATE TABLE IF NOT EXISTS demo_table (
        column1 VARCHAR ( 20000 ),
        column2 VARCHAR ( 20000 ),
        column3 VARCHAR ( 20000 ),
        column4 VARCHAR ( 20000 )
    ) ENGINE = INNODB CHARACTER SET latin1;
如果这样创建则会直接抛出和文章开头给出的错误一样,这就是我们设计表的时候行大小超过了 65535,
我这里都用20000一个字段,4个字段的行大小就直接8万了
遇到这样问题我们可以稍加改造,更改列为TEXT可以避免MySQL 65535字节的行大小限制,
而InnoDB变长列的页外存储可以避免InnoDB行大小限制。(使用BLOB和TEXT类型都可以页外存储,因为是文本,所以用TEXT)
    CREATE TABLE IF NOT EXISTS demo_table (
        column1 VARCHAR ( 20000 ),
        column2 VARCHAR ( 20000 ),
        column3 VARCHAR ( 20000 ),
        column4 TEXT    
    ) ENGINE = INNODB CHARACTER SET latin1;
-- 注:这里的TEXT类型也占了10个字节

2:变长限制

  为了可以更好的了解这个行长限制,这里我就利用行长的边界值进行一个说明;行长最大限制65535

注:字段设置允许为NULL时需要占用一个字节
注:在varchar类型长度0到255之间(包含255)则需要1个字节记录长度;超过255~65535则需要2个字节记录长度


    CREATE TABLE IF NOT EXISTS test ( 
        t1 VARCHAR ( 65533 ) NOT NULL 
    ) charset latin1;



    CREATE TABLE IF NOT EXISTS test ( 
        t1 VARCHAR ( 21844 ) NOT NULL ,
        t2 TINYINT NOT NULL
    ) charset utf8mb3;

    所以65533 取模 3 = 21844;所以t1占用21844
    为什么是65533取模3,因为t1需要提前预留2个字节记录长度
    那21844*3+2=65534;这时还剩余一个字节就分配给t2,因为t2占用一个字节的

设置为允许 NULL
说明:我们再上面创建表字段后面会跟NOT NULL;那是因为我不设置NOT NULL的话,那就代表可以存入
NULL值;但是官方定义可以为NULL的字段需要加一个字节专门记录NULL值

    CREATE TABLE IF NOT EXISTS test ( 
        t1 VARCHAR ( 65532 )
    ) charset latin1;

注:具体介绍看MySQL官网说明

MySQL 表列数和行大小有哪些限制?

列数限制

MySQL对每个表有4096列的硬限制,但是对于给定的表,有效最大值可能会更少。确切的列限制取决于几个因素:

  • 表的最大行大小限制了列的数量(可能还有大小),因为所有列的总长度不能超过该大小

  • 个列的存储要求限制了给定最大行大小内的列数。某些数据类型的存储要求取决于存储引擎,存储格式和字符集等因素

  • 存储引擎可能会施加其他限制表列计数的限制。例如, InnoDB每个表的限制为1017列

  • 功能键部分被实现为隐藏的虚拟生成的存储列,因此表索引中的每个功能键部分都计入表的总列数限制。

MySQL 表列数和行大小有哪些限制?

行大小限制

给定表的最大行大小由几个因素决定:

  • MySQL表的内部表示具有65,535字节的最大行大小限制,即使存储引擎能够支持更大的行也是如此。BLOBTEXT列仅有助于朝向行大小限制9〜12字节,因为它们的内容是从该行的其余部分分开存储。

  • InnoDB 对于4KB,8KB,16KB和32KBinnodb_page_size 设置,表 的最大行大小(适用于本地存储在数据库页面内的数据)略小于页面的一半 。例如,对于默认的16KBInnoDB页面大小,最大行大小略小于8KB 。对于64KB页面,最大行大小略小于16KB

  • 如果包含 可变长度列的InnoDB 行超出最大行大小,请InnoDB选择可变长度列进行外部页外存储,直到该行适合InnoDB 行大小限制。对于行外存储的变长列,本地存储的数据量因行格式而异。

  • 不同的存储格式使用不同数量的页面标题和尾部数据,这会影响行可用的存储量(这里不做展开,感兴趣的可以查阅官网了解详情)


行大小限制案例
MySQL 表列数和行大小有哪些限制?
MySQL 表列数和行大小有哪些限制?

在下面的MyISAM例子中,改变柱TEXT 避免了65535字节的行大小限制,并且允许成功,因为操作 BLOB和 TEXT列仅有助于朝向行大小9至12个字节。

MySQL 表列数和行大小有哪些限制?

操作成功执行InnoDB 表,因为更改列以 TEXT避免MySQL 65,535字节行大小限制,并且InnoDB 可变长度列的页外存储避免了 InnoDB行大小限制。

MySQL 表列数和行大小有哪些限制?

可变长度列的存储包括长度字节,它们被计入行大小。例如, VARCHAR(255) CHARACTER SET utf8mb3列需要两个字节来存储值的长度,因此每个值最多可以占用767个字节。


t1 由于列需要32,765 + 2个字节和32,766 + 2个字节,因此 创建表的语句成功,最大行大小为65,535字节:

MySQL 表列数和行大小有哪些限制?

将列长度减少到65,533或更少可允许语句成功。

MySQL 表列数和行大小有哪些限制?

对于MyISAM表, NULL列需要行中的额外空间才能记录其值 NULL。每NULL 列需要一位额外的值,向上舍入到最接近的字节。


创建表的语句t3失败,因为除了可变长度列长度字节所需的空间之外,还MyISAM需要NULL列的空间,导致行大小超过65,535字节:

MySQL 表列数和行大小有哪些限制?

InnoDB将行大小(对于数据库页面中本地存储的数据)限制为略小于4KB,8KB,16KB和32KB innodb_page_size 设置的数据库页面的一半,对于64KB页面,将行大小限制 为略小于16KB。

t4由于定义的列超过16KB InnoDB页面的行大小限制,因此 创建表的语句失败。

- END -


往期推荐