• InnoDB行格式(3)VARCHAR最多能存储的数据


    InnoDB存储引擎VARCHAR最多能存储的数据

    前言

    我们知道在InnoDB存储引擎中,行格式Compact、Compressed、Dynamic都会计算变长字段VARCHAR长度列表,这个字段长度一般采用两个字节表示,也就是VARCHAR能表示的最大长度应该是2的16次方(因为一个字节8位,两个字节16位能表示的最大值是65535),那么65535个字节长度是否能存放呢?测试案例如下

    mysql> create table test_varchar_size(
        -> c varchar(65535)
        -> )CHARSET=ascii ROW_FORMAT=Compact;
    ERROR 1118 (42000): 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    分析

    很明显错误信息提示,我们列c设置的长度太长,注意**MySQL对一条记录占用最大的空间有限制,所有列(不包含隐藏列和记录头信息)长度之和需要小于65535,当然这并不包含TEXT或者BLOBs类型的列。**也就是说test_varchar_size测试表还有其它数据占据空间,我们先来分析一条数据的基本信息,以Compact行格式为例

    这里的长度不计算记录头信息以及隐藏列那么还剩下如下三部分数据

    • 字段的真实数据。

    • 字段的长度数据。

    • 字段的NULL值列表。

    ascii字符集

    字段的长度数据也就是长度列表最大两个字节,字段c没有指明not null所以占用一个字节(只有一个字段其实只占用了一个bit位,但需要用一整个字节表示所以高位补0),而test_varchar_size测试表的的字符集为ascii,只需要用一个字节就可以表示一个字符,其余编码集可以参考如下数据。

    ### 查询所有的字符集,总共有41种下面抽取常见字符集
    ### Maxlen表示一个字符最大需要几个字节表示
    mysql> show charset;
    +----------+---------------------------------+---------------------+--------+
    | Charset  | Description                     | Default collation   | Maxlen |
    | latin1   | cp1252 West European            | latin1_swedish_ci   |      1 |
    | ascii    | US ASCII                        | ascii_general_ci    |      1 |
    | gb2312   | GB2312 Simplified Chinese       | gb2312_chinese_ci   |      2 |
    | gbk      | GBK Simplified Chinese          | gbk_chinese_ci      |      2 |
    | utf8     | UTF-8 Unicode                   | utf8_general_ci     |      3 |
    | utf8mb4  | UTF-8 Unicode                   | utf8mb4_general_ci  |      4 |
    .......
    +----------+---------------------------------+---------------------+--------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    所以采用ascii的测试表test_varchar_size唯一c字段长度应该为

    65535 - 2(变长字符长度列表)-1(NULL值列表)= 65532

    mysql> create table test_varchar_size(
        -> c varchar(65532)
        -> )CHARSET=ascii ROW_FORMAT=Compact;
    Query OK, 0 rows affected (0.01 sec)
    
    • 1
    • 2
    • 3
    • 4

    在上面分析中我们提到了字符集影响字段c的最大长度,那么非ascii是如何影响的呢?往下面走

    gbk字符集

    通过show charset like '%gbk%';命令我们可以得到gbk一个字符最大需要两个字节才能表示,演示如下

    mysql> show charset like '%gbk%';
    +---------+------------------------+-------------------+--------+
    | Charset | Description            | Default collation | Maxlen |
    +---------+------------------------+-------------------+--------+
    | gbk     | GBK Simplified Chinese | gbk_chinese_ci    |      2 |
    +---------+------------------------+-------------------+--------+
    1 row in set (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    那么采用gbk字符c字段能表示的最大长度应该为

    65535 - 2(变长字符长度列表)-1(NULL值列表)= 65532

    65532 / 2 = 32766

    结果验证如下

    mysql> create table test_varchar_size(
        -> c varchar(32767)
        -> )CHARSET=gbk ROW_FORMAT=Compact;
    ERROR 1118 (42000): Row size too large. The maximum row size 
    for the used table type, not counting BLOBs.......
    
    mysql> create table test_varchar_size(
        -> c varchar(32766)
        -> )CHARSET=gbk ROW_FORMAT=Compact;
    Query OK, 0 rows affected (0.01 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    utf8字符集

    utf8字符集验证和gbk字符集验证类似,因为utf8一个字符需要三个字节表示,所以c字段能表示的最大长度就是

    65532 / 3 = 21844

    注意

    上面分析时只采用了一个字段,并且字段c是允许为空的,就直接采用上面的规则分析,如果c字段设置了NOT NULL那么就不需要65535-1的操作,实际分析时需要根据情况具体分析。

  • 相关阅读:
    QT Creator概览
    华为云云耀云服务器L实例评测|企业项目最佳实践之私有库搭建verdaccio(八)
    JAVA IO——文件拷贝
    【开发经验】gateway网关开发调试优先选择本地服务
    谈谈Go语言中函数的本质
    截图快捷键ctrl加什么
    924. 尽量减少恶意软件的传播 前缀和
    【git】Git 指令统计代码行数
    进程与线程(四)
    超强满血不收费的AI绘图教程来了(在线Stable Diffusion一键即用)
  • 原文地址:https://blog.csdn.net/zzf1233/article/details/126069082