问题
1、本文旨在阐明一些在解决这些问题过程中感到迷惑的点。
2、笔者的测试环境是 Mysql 5.7 ,引擎是innoDB,采用的编码是UTF-8(每个汉子3个字节)。
- varchar()的长度怎么计算?
- varchar(255) 与 varchar(256) 的区别在哪里?
解析
varchar()的长度怎么计算?
4.0版本以下,varchar(20),指的是20字节。
5.0版本以上,varchar(20),指的是20字符。
首先明确长度概念,我理解这里涉及的长度应该有四种:字符串的字节长度
、字符串的字符长度
、字段的实际长度
、索引长度(字符串最大长度)
。
CREATE TABLE test (
name VARCHAR(100) DEFAULT NULL,
) CHARSET=utf8;
-
插入100个汉字。
各值应为:
字符串的字节长度
: 3 * 100 = 300 字节。Mysql length() 函数可得
字符串的字符长度
: 100个汉字即 100个字符。Mysql char_length() 函数可得
字段的实际长度
: 3 * 100 + 1 + 2 = 303 字节。 其中 1 为 null 标识位,2 为varchar实际长度标识位。
索引长度(字符串最大长度)
: 3 * 100 + 1 + 2 = 303 字节。 当字段存满时其值等于字段实际长度。 -
插入50汉字50英文。
各值应为:
字符串的字节长度
: 3 * 50 + 50 = 200 字节。 Mysql length() 函数可得
字符串的字符长度
: 50汉字,50英文即 100个字符。Mysql char_length() 函数可得
字段的实际长度
: 3 * 50 + 50 + 1 + 1 = 202 字节。 其中 1 为 null 标识位,1 为varchar实际长度标识位。
索引长度(字符串最大长度)
: 3 * 100 + 1 + 2 = 303 字节。
以上示例可能产生一些疑惑的点在于,两个标识位的算法(null标识位、varchar实际长度标识位)。
对这里有疑惑的同学,建议先看一下 Mysql 行存储 的规则,我在这里仅做一个简单的描述:
null标识位
: 每一个允许为空的字段都需要标识它在当前行里是否为空。
具体算法是 (N + 7)/ 8 ,其中N代表该表中允许为空的字段数。
举个例子: 1 字节 = 8 比特位,每个比特位可以用0 / 1来标识一个字段是否为空,即8个比特位就能标识8个字段。
varchar实际长度标识位
: Mysql 在读取行记录时,需要知道varchar实际存了多长,才能知道要读出几位数据。1 字节 = 8比特位 ,2 ^ 8 = 256 ,即可以标识 0 ~ 255 ; 2 字节 = 16 比特位 ,2 ^ 16 = 65536 ,即可以标识 0 ~ 65535 ,因此最多仅需要 2 字节位即可标识实际长度。
varchar(255) 与 varchar(256) 的区别在哪里?
之前看到大佬设置 varchar(255) 很好奇有什么用,简单查阅以后得知,256 需要两个标识位,255需要一个标识位,记下以后满意的离去了。
后来探究varchar长度计算方式的时候发现了问题,假如我们设定字段类型为 varchar(255) ,那我存放255个汉字,字符串的字节长度应为 255 * 3 = 765 ,765 是不能用1个字节标识的。
实际上varchar(255)和varchar(256)的区别在于索引,Mysql 5.6 之前 索引最大的长度是 767 字节 。而 767 / 3 ≈ 255 ,正好支持索引的建立。(这个地方属于个人理解,没在老版本验证,有懂的大佬忘及时纠正)
参考资料
三篇博文有一些本人认为描述不太正确的地方,因为没有去翻官网资料,没办法下结论。各位看客自行分辨。
https://blog.csdn.net/yinjinshui/article/details/102496340
https://blog.csdn.net/qq_30336433/article/details/81669957
https://liuchenyang0515.blog.csdn.net/article/details/117524328