专栏首页谭小谭varchar有最大长度限制吗

varchar有最大长度限制吗

先说结论,mysql 中的 varchar 是有最大长度限制的,这个值是 65535 个字节。

varchar(100),这个 100 的单位是啥,这个单位其实在不同版本中是不一样的。

在早期低版本中代表的是字节,具体哪个版本我也没去验证了,后来被改成了字符,不过可以肯定的是在 5.1 版本后, varchar(100) 就是指 100 个字符。

说到 varchar ,一般都会拿 char 来做比较说明。

char 是固定长度,其单位也是字符,比如 char(10),就表示不管你给的什么值,都会被 mysql 固定保存成 10 个字符。

如果给的字符长度小于 10,那么在尾部就会自动用空格补齐。

如果大于 10,在严格模式(strict sql mode)下就会报错,在非严格模式下就会对内容做自动截取操作。

另外 char 也是有最大长度限制的,最大长度为 255, 即 char 类型最多只能保存 255 个字符,char(256) 这都是错误的写法,可以看下面的例子。

##创建一个表,同时声明address字段长度为256会报错,最大为255
mysql> create table test2 ( address char(256) );
ERROR 1074 (42000): Column length too big for column 'address' (max = 255); use BLOB or TEXT instead

下面是 char 和 varchar 对于同一个字符所需要的不同的存储空间,这里假设使用的是 latin1 单字节字符集。

CHAR(4)

存储空间大小(字节)

VARCHAR(4)

存储空间大小(字节)

''

' '

4 bytes

''

1 byte

'ab'

'ab '

4 bytes

'ab'

3 bytes

'abcd'

'abcd'

4 bytes

'abcd'

5 bytes

'abcdef'

'abcd'

4 bytes

'abcd'

5 bytes

细心的你可能会发现 varchar 的存储空间会比字符的实际长度多 1 个字节,这是因为 varchar 需要额外增加 1 到 2 个字节来存储字符的长度,这个值被称作前缀

也就是说在 varchar 类型中,除了字符本身实际占用的空间外,还需要 1 个或 2 个字节来声明这个字符的长度。

如果存储的值小于 255 个字节,则使用 1 个字节来存储前缀,如果大于 255 个字节则使用 2 个字节来存储前缀。

关于字符集和字节的关系,以及字节 (byte) 与位 (bit) 的关系。

1 byte (字节) = 8 bit (位)

2^8 = 256

所以计算机里常见的 255、256 临界值绝大多数与这个有关

1 个字节具体占多大的空间,这与所使用的字符集有关系

比如 latin1 单字节字符集,1 个字符即占 1 个字节

我们常见的 GBK、UTF8、UTF8-MB4 这些都是多字节字符集

GBK :一个字符最多占 2 个字节
UTF8:一个字符最多占 3 个字节
UTF8MB4:一个字符最多占 4 个字节

好了,再坚持一会,回到文章开头的问题,为啥 varchar 最大长度是 65535 个字节呢,其实这个是受 mysql 另一个规则限制导致的,mysql 规定了每行数据大小不能超过 65535 个字节

另外还有一个小问题,一个字段如果允许为 null ,在 mysql 中也是需要增加额外空间来单独标识的,反之则不需要这个额外空间,至于这个空间大小具体是怎么计算的,我目前也还没有研究过。

结合上面说的几点,下面来通过几个实例来验证下。

##字符集设置为latin1,1个字符=1个字节,字段允许为null
mysql> create table test ( address varchar(65536) default null ) charset=latin1;
ERROR 1074 (42000): Column length too big for column 'address' (max = 65535); use BLOB or TEXT instead

##减去varchar前缀长度标识2个字节,还是报错,说明null标识也占用了空间
mysql> create table test ( address varchar(65533) default null ) charset=latin1;
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
##把字段设置为非空即可建表成功
mysql> create table test ( address varchar(65533) not null ) charset=latin1;
Query OK, 0 rows affected (0.01 sec)
##如果字符集设置为UTF8,那么 max=65535/3=21845,一个字符最多占3个字节
mysql> create table test2 ( address varchar(65533) not null ) charset=UTF8;
ERROR 1074 (42000): Column length too big for column 'address' (max = 21845); use BLOB or TEXT instead

基于上面几个实例,基本上可以得出计算 varchar 最大长度限制的公式。

varchar 最大长度限制 = (行最大字节数(65535) - null 标识字节数 - 长度前缀字节数(1或2)) / 字符集单字符占用最多字节数

看到这里,不知道你有没有一个疑问,为什么长度前缀 1 或 2 个字节就够用了呢,因为 2 个字节的话,2^16 = 65536,这已经超过 mysql 行最大字节数 65535 的限制了,所以 1 到 2 个字节就够用了。

最后再看一个综合例子,我们创建一个表,采用 UTF8 字符集,添加两个非空字段,分别为 char 和 varchar 类型,char 类型长度给定为 255。

那么 varchar 类型字段的最大字节数应该就是,

65535 (行最大字节数) - 255*3 (一个字符最多占 3 个字节) = 64770,

然后再减去 2 个长度前缀字节,

64770 - 2 = 64768,

最后再算出 varchar 最大字符数为 64768 / 3 = 21589.33,

##字符数21590超过最大字符数会报错
mysql> create table test4 (name char(255) not null, address varchar(21590) not null ) charset=utf8;
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
##字符数21589则刚好能创建成功
mysql> create table test4 (name char(255) not null, address varchar(21589) not null ) charset=utf8;
Query OK, 0 rows affected, 1 warning (0.02 sec)

好了,关于 varchar 的最大长度问题就聊到这了,文中如有错误,欢迎大家批评指出,更欢迎大家交流讨论,如果文章对你有帮助,点个在看表示对我的支持哈,感谢。

推荐文章:

最近发现一个可以捡零花钱的活

mysql为什么建议使用自增主键

如何分析一条sql的性能

本文分享自微信公众号 - 谭小谭(tanstory),作者:谭小谭啊

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-01-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • mysql为什么建议使用自增主键

    前面我写了几篇关于 mysql 索引的文章,索引是 mysql 非常重要的一部分。你也可能经常会看到一些关于 mysql 军规、mysql 查询优化的文章,其实...

    谭小谭
  • 下载抖音无水印视频

    只要一刷抖音视频,基本上就是停不下来,看到一些喜欢的视频,就想下载下来,但是通过正常手段下载的视频都会带有抖音的水印,今天就一起来使用非正常手段来看看怎么获取无...

    谭小谭
  • 自制手写稿处理神器

    今天分享一个 GitHub 上一个实用神器,可以让你的手写稿图片变清晰、图片大小变更小。

    谭小谭
  • 【Mysql】varchar类型

    (1)varchar (N):中的N指的是字符的长度,即:该字段最多能存储多少个字符(characters),不是字节数。不管是一个中英文字符或者数字、或者一个...

    用户5522200
  • Greenplum常用导数据方法及性能测试

    # 生成隐藏字符 soh=`echo 1 | awk '{printf("%c", $1)}'` replaceWord=$1

    小徐
  • MySQL的启动原理

    我们知道mysql.server,mysqld_safe和mysqld都是可以用来启动mysql服务,他们之间是有区别的。这三个命令中,其中mysql.ser...

    AsiaYe
  • 【腾讯内部干货分享】安卓包体压缩——分析Dalvik字节码进行减包优化

    对游戏整体的压缩却不影响场景,对图片的压缩却不影响品质。最麻烦的是对代码进行压缩,简直是让程序们熬白了头发只为包体再小个几K。

    WeTest质量开放平台团队
  • mysql开启数据库记录日志

    程序出错时,几乎占了一半是写错了sql语句,而定位出错位置和找错是非常麻烦的,这时候就可以借助mysql的日志记录

    仙士可
  • 社会化登录是什么?企业是否值得实施?

    社会化登录,是指用户使用社交平台的身份认证信息在第三方应用或网址进行认证登录的流程,比如大家经常使用个人微信、QQ、微博等社交账号登录滴滴、网易云音乐等。社会化...

    玉符IDaaS
  • MySQL数据类型(r3笔记第87天)

    今天在本地装了一个MySQL的学习环境,简单的熟悉了一下。准备开始好好学习MySQL了。 学习编程语言我都是从数据类型入手。每种编程语言的数据类型都有自己的特点...

    jeanron100

扫码关注云+社区

领取腾讯云代金券