MySQL的varchar定义长度到底是字节还是字符

本文详细解析了MySQL中字符与字节的概念区别,并通过具体示例对比了不同字符集下varchar与char类型的长度限制。

相信这个问题也会困扰不少人,尤其是使用过其它数据库(如Oracle)的人,之前我也没有太在意这个问题,再加上一些书籍和网上的文章讲的不够细致,又没测试过,导致我一直理解错误。下面通过实例来解释,在开始之前先简单介绍下字符和字节的区别。
字符 人们使用的记号,抽象意义上的一个符号。一个汉字和英文就是一个字符,如'1', '中', 'a', '$', '¥',…… 
字节 计算机中存储数据的单元,一个8位的二进制数,是一个很具体的存储空间,如0x01, 0x45, 0xFA,……
详细的可以参考http://www.regexlab.com/zh/encoding.htm,正确理解相关概念还是很重要的。
好了,如果你已经理解了字符和字节的区别,下面就容易多了。
环境:CentOS5.x,MySQL5.1.x
UTF8字符集下:
SQL>create table test(id int auto_increment,name varchar(10),primary key(id));
SQL>insert into test values(null,'1234567890');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values(null,'一二三四五六七八九十');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values(null,'abcdefghig');
Query OK, 1 row affected (0.01 sec)
SQL>insert into test values(null,12345678901);
ERROR 1406 (22001): Data too long for column 'name' at row 1
SQL>insert into test values(null,'一二三四五六七八九十1');
ERROR 1406 (22001): Data too long for column 'name' at row 1
SQL>insert into test values(null,'一二三四五六七八九十一');
ERROR 1406 (22001): Data too long for column 'name' at row 1
SQL>select id,name,length(name),char_length(name) from test;

  
  1. +----+--------------------------------+--------------+-------------------+  
  2. | id | name                           | length(name) | char_length(name) |  
  3. +----+--------------------------------+--------------+-------------------+  
  4. |  1 | 1234567890                     |           10 |                10 |  
  5. |  2 | 一二三四五六七八九十            |           30 |                10 |  
  6. |  3 | abcdefghig                     |           10 |                10 |  
  7. +----+--------------------------------+--------------+-------------------+  
  8. rows in set (0.00 sec) 

GBK字符集下:
SQL>create table test(id int auto_increment,name varchar(10),primary key(id));
SQL>insert into test values(null,'1234567890');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values(null,'一二三四五六七八九十');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values(null,'abcdefghig');
Query OK, 1 row affected (0.01 sec)
SQL>insert into test values(null,12345678901);
ERROR 1406 (22001): Data too long for column 'name' at row 1
SQL>insert into test values(null,'一二三四五六七八九十1');
ERROR 1406 (22001): Data too long for column 'name' at row 1
SQL>insert into test values(null,'一二三四五六七八九十一');
ERROR 1406 (22001): Data too long for column 'name' at row 1
SQL>select id,name,length(name),char_length(name) from test;

  
  1. +----+----------------------+--------------+-------------------+  
  2. | id | name                 | length(name) | char_length(name) |  
  3. +----+----------------------+--------------+-------------------+  
  4. |  1 | 1234567890           |           10 |                10 |  
  5. |  2 | 一二三四五六七八九十  |           20 |                10 |  
  6. |  3 | abcdefghig           |           10 |                10 |  
  7. +----+----------------------+--------------+-------------------+  
  8. rows in set (0.00 sec) 

由此可见,varchar定义的长度的单位是字符,哪怕是1个多字节字符也是1个字符,如中文和英文字母都被当作1个字符来对待。
那么varchar能够定义的最大长度是多少呢?这个和你当前所使用的字符集有关。抛开字符,其最大长度为65535字节(这是最大行大小,由所有列共享),而放在不同的字符集下,能够定义的最大长度就会有所不同,如UTF8下是21845。据说MySQL5中varchar的长度也为字符,而MySQL4中的则为字节,未经证实,感兴趣的有环境可以自己测下。
顺便补充一下,char数据类型定义的长度也为字符,其最大长度为255。
SQL>create table test(id int auto_increment,name char(5),primary key(id));
Query OK, 0 rows affected (0.09 sec)
SQL>insert into test values(null,'123');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values(null,'12345');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values(null,'一二三');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values(null,'一二三四五');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values(null,123456);
ERROR 1406 (22001): Data too long for column 'name' at row 1
SQL>insert into test values(null,'一二三四五1');
ERROR 1406 (22001): Data too long for column 'name' at row 1
SQL>select id,name,length(name),char_length(name) from test;

  
  1. +----+-----------------+--------------+-------------------+  
  2. | id | name            | length(name) | char_length(name) |  
  3. +----+-----------------+--------------+-------------------+  
  4. |  1 | 123             |            3 |                 3 |  
  5. |  2 | 12345           |            5 |                 5 |  
  6. |  3 | 一二三           |            9 |                 3 |  
  7. |  4 | 一二三四五       |           15 |                 5 |  
  8. +----+-----------------+--------------+-------------------+  
  9. rows in set (0.00 sec) 

http://cau99.blog.51cto.com/1855224/383023

<think>首先,用户的问题是:“我想了解MySQLVARCHAR类型是基于字符长度还是字节长度进行存储 请问MySQL VARCHAR类型是按字符长度还是字节长度定义”。这是一个关于MySQL数据库的VARCHAR类型定义的问题。 我需要参考提供的引用内容来回答这个问题。引用内容如下: - 引用[1]:在MySQL 5.X以上的版本中,VARCHAR(20)表示字符长度,可以存储20个英文字符20个中文字符。在MySQL 4.X版本中,表示字节长度。 - 引用[2]:VARCHAR类型存储变长字段的字符类型,存储时需要前缀长度列表。如果字符长度小于255字节,需要1字节空间;如果大于255字节,需要2字节空间。 - 引用[3]:在MySQL 5.0以上版本,VARCHAR的最大长度是65535字节,但受限于最大行长度。65535字节包括所有字段的长度、变长字段的长度标识和NULL标志位。 - 引用[4]:在UTF8MB4字符集下,一个中文汉字占3个字节。例如,VARCHAR(60)存储“万科”,实际长度是6字节。 - 引用[5]:在Oracle中,可以用字符为单位定义VARCHAR2字段,但MySQL类似。 从这些引用中,我可以总结出: - 在MySQL中,VARCHAR类型定义长度指的是字符长度,而不是字节长度。具体来说: - MySQL 5.X及以上版本:VARCHAR(n) 中的n表示最大字符数。 - MySQL 4.X版本:表示字节长度。 - 实际存储时,VARCHAR是变长的,存储字节数取决于字符集和实际内容。例如,在UTF8MB4字符集下,一个中文字符占用3个字节,所以VARCHAR(10)可以存储10个字符,但每个字符可能占用多个字节。 用户的问题直接问“是按字符长度还是字节长度定义”,所以我需要明确回答:在MySQL中,VARCHAR类型定义长度是基于字符长度的(在MySQL 5.X及以上版本)。 现在,回答结构需要清晰,帮助用户逐步解决问题。系统指令要求: - 回答结构清晰。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,如[^1]。 - 所有行内数学表达式用$...$,独立公式用$$...$$,但这个问题可能不需要数学表达式,除非涉及计算。 - 保证回答真实可靠。 所以,回答结构: 1. **直接回答问题**:明确说明VARCHAR类型定义长度字符长度(在MySQL 5.X及以上)。 2. **解释细节**:描述不同MySQL版本的区别,以及存储机制。 3. **引用支持**:在解释时,引用提供的引用内容。 4. **生成相关问题**:在最后,添加相关问题部分。 最后,添加相关问题。系统指令说“生成相关问题”,并给出示例格式。 相关问题应该基于用户的问题,比如: - VARCHAR的最大长度限制是什么? - 不同字符集如何影响VARCHAR存储? - 如何计算VARCHAR字段的实际存储大小? - MySQL 4.X和5.X的差异? 从引用中,我可以提取一些点。 完整回答结构: - 开头:直接回答。 - 主体:详细解释,分步说明。 - 结尾:相关问题。 添加引用标识:例如,在提到MySQL 5.X时,加[^1]。 现在,草拟回答: 回答: 在MySQL中,VARCHAR类型定义长度是基于字符长度的,而不是字节长度。具体来说: - 在MySQL 5.X及以上版本中,VARCHAR(n) 中的n表示最大字符数。例如,VARCHAR(10)可以存储最多10个字符,无论这些字符是英文还是中文[^1]。 - 在MySQL 4.X版本中,VARCHAR(n) 表示字节长度存储时会根据字符集计算字节数[^1]。 实际存储时,VARCHAR是变长字符串类型。存储字节数取决于字符集和实际内容。例如: - 在UTF8MB4字符集下,一个中文字符通常占用3个字节[^4]。 - 存储机制包括前缀长度标识:如果字符长度小于255字节,需要1字节的前缀;如果大于255字节,需要2字节的前缀[^2]。 此外,VARCHAR的最大长度受限于最大行长度(65535字节),但实际可定义长度会因字符集和行中其他字段而不同[^3]。 总之,在大多数现代MySQL版本(5.X及以上),VARCHAR(n) 定义的是字符长度,确保存储时能容纳n个字符。 相关问题: 1. 在MySQL中,如何计算VARCHAR字段的实际存储大小? 2. VARCHARCHAR类型在存储上有什么区别? 3. 不同字符集(如UTF8MB4 vs LATIN1)如何影响VARCHAR存储空间? 4. 在MySQL 4.X版本中,VARCHAR定义方式有什么不同? 确保引用正确: - 对于MySQL 5.X版本字符长度:[^1] - 对于存储机制:[^2]和[^3] - 对于字符集影响:[^4] 在回答中自然添加引用。</think>### MySQLVARCHAR类型定义长度解析 在MySQL中,VARCHAR类型定义长度**基于字符长度character length)**,而非字节长度(byte length)。以下是详细解释,帮助您逐步理解: 1. **MySQL版本差异**: - **MySQL 5.X及以上版本**:VARCHAR(n) 中的 `n` 表示最大字符数(character count)。例如,`VARCHAR(10)` 可以存储最多10个英文字符或10个中文字符(无论字符占用多少字节),定义时以字符为单位[^1]。 - **MySQL 4.X版本**:VARCHAR(n) 中的 `n` 表示字节长度(byte length),存储时会根据字符集动态计算字节数[^1]。但由于MySQL 4.X已过时,现代应用通常使用5.X及以上版本,因此字符长度是主流定义方式。 2. **存储机制**: - VARCHAR是变长字符串类型,实际存储字节数取决于字符集(character set)和具体内容。例如: - 在UTF8MB4字符集下,一个英文字符占用1字节,一个中文字符占用3字节[^4]。 - 存储时需添加前缀长度标识:如果字符长度小于255字节,前缀占用1字节;如果大于255字节,前缀占用2字节[^2]。 例如,定义 `VARCHAR(60)` 并存储 "万科"(2个中文字符),在UTF8MB4下实际字节长度为6字节2字符 × 3字节/字符),但定义长度60表示最多可容纳60个字符[^4]。 3. **最大长度限制**: - VARCHAR的最大理论长度为65535字节(包括所有字段长度、变长字段标识和NULL标志位),但实际可定义的最大字符数受字符集影响。例如: - 在LATIN1字符集(单字节字符)下,`VARCHAR(65535)` 可能有效。 - 在UTF8MB4字符集(多字节字符)下,最大字符数约为65535/3 ≈ 21845字符(需考虑行大小限制)[^3]。 实际使用中,需通过 `SHOW TABLE STATUS` 或计算行大小来验证。 4. **与字节长度的关系**: - 虽然定义基于字符长度,但实际存储占用字节数需通过函数如 `LENGTH()`(字节长度)和 `CHAR_LENGTH()`(字符长度)计算。例如: ```sql SELECT name, CHAR_LENGTH(name) AS char_len, LENGTH(name) AS byte_len FROM users; ``` 在UTF8MB4下,若 `name VARCHAR(10)` 存储 "Hello"(5字符),则 `char_len=5`,`byte_len=5`;若存储 "你好"(2字符),则 `byte_len=6`[^4]。 **总结**:在MySQL 5.X及以上版本中,VARCHAR(n) 的 `n` 明确表示字符长度,确保用户定义时无需考虑字节转换。存储引擎会根据字符集自动处理字节级细节,但需注意字符集选择对实际存储空间的影响(如UTF8MB4比LATIN1占用更多字节)[^1][^2][^3][^4]。 ### 相关问题 1. 如何计算MySQLVARCHAR字段的实际存储大小(包括前缀和字符集影响)? 2. VARCHARCHAR类型在存储机制和性能上有何区别? 3. 不同字符集(如UTF8MB4、LATIN1)如何影响VARCHAR的最大可定义长度? 4. 在MySQL中,如何优化VARCHAR字段以减少存储空间占用?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值