MySQL中CHAR和VARCHAR类型的区别

本文深入探讨了MySQL数据库中CHAR和VARCHAR两种数据类型的存储方式、长度限制及尾部空格处理的区别,帮助开发者更好地理解这两种类型的应用场景。

    CHAR和VARCHAR类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。

    CHAR和VARCHAR类型声明的长度表示你想要保存的最大字符数。例如,CHAR(30)可以占用30个字符。

    CHAR列的长度固定为创建表时声明的长度。长度可以为从0到255的任何值。当保存CHAR值时,在它们的右边填充空格以达到指定的长度。当检索到CHAR值时,尾部的空格被删除掉。在存储或检索过程中不进行大小写转换。

    当试图创建一个char(256)的字段时,会提示如下错误:
    Column length too big for column 'name' (max = 255)

    VARCHAR列中的值为可变长字符串。长度可以指定为0到65,535之间的值。(VARCHAR的最大有效长度由最大行大小和使用的字符集确定。整体最大长度是65,532字节)。

    当试图创建一个varchar(65535)的字段时,会提示如下错误:
    Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs
    只能创建长度最大为65532的varchar类型。

    同CHAR对比,VARCHAR值保存时只保存需要的字符数,另加一个字节来记录长度(如果列声明的长度超过255,则使用两个字节)。

    VARCHAR值保存时不进行填充。当值保存和检索时尾部的空格仍保留,符合标准SQL。

 

 

  注:

    和Oracle数据不同,MySQL中的CHAR和VARCHAR存储时部分全角半角。

    1.MySQL中的char(5), 最多可以存储5个全角,最多也只能存储5个半角。

    2.Oracle中的char(5), 最多只能存储2个全角字符加1个半角,或最多只能存储5个半角。

<think>我们讨论MySQL中的CHARVARCHAR类型区别:1.储方式:-CHAR:固定长度。当定义一个CHAR(10)的字段时,无论实际储的字符串长度是多少,它都会占用10个字符的储空间(如果字符集是单字节的,则是10个字节;如果是多字节字符集,则可能占用更多字节)。如果储的字符串长度小于定义的长度,会在右边填充空格以达到指定长度。当检索CHAR值时,尾部的空格会被移除(除非设置了PAD_CHAR_TO_FULL_LENGTH模式)。-VARCHAR:可变长度。VARCHAR(10)的字段,如果储的字符串长度为5,则只占用5个字符的空间(另外需要1或2个字节来储长度信息,因为VARCHAR类型在数据前有一个或两个字节的前缀表示长度,当长度<=255时用1个字节,否则用2个字节)。储时不会填充空格,检索时也不会移除尾部空格(但要注意,在插入时如果字符串尾部有空格,是会保留的,除非超过列定义的长度会被截断)。2.储空间:-CHAR类型会占用定义长度的空间,即使实际内容较少。-VARCHAR类型只占用实际储数据的长度加上长度前缀的空间。3.性能:-由于CHAR是固定长度,所以对于经常变更的数据,CHAR类型不容易产生碎片。对于长度变化不大的数据(如MD5值),使用CHAR性能可能更好,因为检索更快。-VARCHAR类型由于长度可变,在更新时如果长度变化,可能导致额外的操作(如页分裂),所以更新频繁且长度变化大的字段使用VARCHAR可能影响性能。4.最大长度:-CHAR最大长度为255个字符(与字符集有关,如果是utf8mb4,每个字符最多4字节,那么一个CHAR(255)列最多需要255*4=1020字节,但实际储时,MySQL对每个行有最大限制,通常是65535字节,所以还要考虑整行的总大小)。-VARCHAR的最大长度也是受行大小限制,但VARCHAR可以定义更长(例如65535字节,但实际可用长度会减去长度前缀其他列所占空间,并且也受字符集影响)。在MySQL5.0.3之前,VARCHAR最大长度为255字节,之后版本最大长度为65535字节(注意是字节,而不是字符,所以对于多字节字符集,实际字符数会减少)。5.空格处理:-在储时,CHAR类型会在值不够长度时填充空格,检索时默认会去掉尾部空格(除非设置SQL模式为PAD_CHAR_TO_FULL_LENGTH)。-VARCHAR类型储时不会填充空格,检索时也不会去掉尾部空格。例子:假设有一个表:CREATETABLEtest(aCHAR(10),bVARCHAR(10));插入数据:INSERTINTOtest(a,b)VALUES('x','x');在CHAR列a中,储的实际是'x'(后面9个空格),但在查询时,SELECTa,LENGTH(a)FROMtest;返回的a是'x'(去掉尾部空格),LENGTH(a)返回1(去掉空格后的长度)。而b列返回的则是'x',LENGTH(b)也是1。但是,如果使用SELECTa,HEX(a)FROMtest;可以看到CHAR储的实际数据(在非严格模式下,如果使用PAD_CHAR_TO_FULL_LENGTH,则返回时会保留空格)。另外,如果插入的字符串尾部有空格,在CHAR列中会被去掉(因为储时会填充到固定长度,然后检索时又去掉填充的空格,所以相当于原始字符串尾部的空格也会被去掉)。而在VARCHAR列中,尾部空格会被保留。例如:插入('x','x'),然后查询:-CHAR列a会返回'x'(去掉尾部空格)-VARCHAR列b会返回'x'(保留空格)注意:在比较时,MySQL会忽略尾部的空格(对于CHARVARCHAR都是如此,但TEXT类型不会)。例如:SELECT*FROMtestWHEREa='x';--会匹配到'a'列值为'x'的行SELECT*FROMtestWHEREb='x';--不会匹配到'b'列值为'x'的行,因为b列保留了空格,而等值比较时,如果比较的字符串没有空格,那么只有没有空格的值才会匹配。但是,如果使用LIKE或者BINARY比较,则不会忽略尾部空格。总结:-当储的数据长度相对固定(例如总是10个字符)时,使用CHAR效率更高。-当储的数据长度变化较大时,使用VARCHAR可以节省储空间。代码示例(创建表):```sql--创建一个表,包含CHARVARCHAR类型CREATETABLEchar_vs_varchar(idINTAUTO_INCREMENTPRIMARYKEY,fixed_lengthCHAR(10),variable_lengthVARCHAR(10));--插入数据INSERTINTOchar_vs_varchar(fixed_length,variable_length)VALUES('abc','abc'),--插入短字符串('abc','abc'),--插入带尾部空格的字符串('abcdefghij','abcdefghij');--插入正好10个字符的字符串--查询数据--使用LENGTH函数(返回字节数,对于'abc',在utf8mb4中,每个英文字符1字节,所以是3)--使用CHAR_LENGTH函数(返回字符数)SELECTfixed_length,LENGTH(fixed_length)ASfixed_length_bytes,CHAR_LENGTH(fixed_length)ASfixed_length_chars,variable_length,LENGTH(variable_length)ASvar_length_bytes,CHAR_LENGTH(variable_length)ASvar_length_charsFROMchar_vs_varchar;--观察尾部空格的影响SELECTCONCAT('"',fixed_length,'"')ASfixed_with_quotes,CONCAT('"',variable_length,'"')ASvar_with_quotesFROMchar_vs_varchar;--比较操作(注意:在比较时,CHARVARCHAR都会忽略尾部空格,除非使用BINARY或LIKE)SELECT*FROMchar_vs_varcharWHEREfixed_length='abc';--会匹配所有fixed_length以'abc'开头(后面有空格)的行,因为比较时忽略尾部空格SELECT*FROMchar_vs_varcharWHEREvariable_length='abc';--只会匹配variable_length为'abc'(没有空格)的行,因为variable_length保了空格,而比较时忽略尾部空格,所以'abc''abc'在比较时都被视为'abc',因此也会匹配?但实际测试中,对于VARCHAR,比较时也会忽略尾部空格,所以也会匹配?--实际上,根据MySQL文档,在比较CHARVARCHARTEXT时,会忽略尾部空格。因此,以下比较是相等的:--'abc'='abc'->true--如果想精确匹配(包括尾部空格),可以使用BINARY运算符:SELECT*FROMchar_vs_varcharWHEREBINARYfixed_length='abc';--不会匹配,因为fixed_length储的是'abc'(7个空格)或者插入时带空格,但检索时去掉了空格?实际上,插入'abc',在fixed_length中储时会被填充为10个字符(后面填充空格),然后检索时去掉尾部空格,所以实际值是'abc'(没有空格),因此等于'abc'。--但是,如果我们插入时是'abc'(3个空格),那么在fixed_length中储的是'abc'(然后填充7个空格?)然后检索时去掉尾部空格,所以得到'abc'(没有空格)。所以,BINARYfixed_length='abc'会匹配,因为比较的是'abc'(去掉尾部空格后的值)'abc'(没有空格)的二进制比较?这有点复杂。--为了验证,我们插入一条记录:INSERTINTOchar_vs_varchar(fixed_length,variable_length)VALUES('abc','abc');--注意:插入fixed_length时,字符串'abc'(5个字符,其中后面3个空格)会被填充为10个字符(后面再补5个空格?),然后检索时去掉所有尾部空格,所以得到'abc'(只有前面3个字符)。--因此,对于fixed_length列,无论插入的字符串尾部有多少空格(除非超过10个字符,会截断),最终检索到的都是去掉尾部空格后的字符串(即原始字符串去掉尾部空格,然后填充到10个字符,再检索时去掉填充的空格,所以最终是原始字符串去掉尾部空格后的结果?)。实际上,在插入CHAR列时,如果字符串尾部有空格,会被当作普通字符,然后在储时填充空格到定义长度,检索时去掉填充的空格,但原始字符串中尾部的空格不会被去掉?不对,根据MySQL文档,当CHAR值时,会去掉尾部的空格(然后填充到指定长度)。所以,插入'abc',储时会先去掉尾部空格变成'abc',然后填充到10个字符(即'abc'),检索时去掉尾部空格得到'abc'。--所以,在插入CHAR列时,字符串尾部的空格会被去掉,然后再填充。因此,插入'abc'插入'abc'的结果是一样的。--对于VARCHAR列,插入时不会去掉尾部空格(除非超过定义长度,会截断并产生警告,如果是严格模式,则报错)。--因此,在比较时,CHAR列的值已经去掉了尾部空格,而VARCHAR列则保留了尾部空格(但比较时,MySQL也会忽略VARCHAR列的尾部空格)。所以,在非二进制比较中,'abc''abc'在CHARVARCHAR列中都会被视作相等。--如果想严格比较(包括空格),可以使用BINARY:SELECT*FROMchar_vs_varcharWHEREBINARYvariable_length='abc';--这样不会匹配'abc',因为二进制比较会考虑空格。--或者使用LIKE:SELECT*FROMchar_vs_varcharWHEREvariable_lengthLIKE'abc';--不会匹配'abc',因为LIKE模式匹配不会忽略尾部空格(除非模式中有通配符)。注意:'abc'模式不会匹配'abc',因为模式'abc'要求后面没有空格。--但注意:LIKE'abc'只匹配正好是'abc'的字符串,而不会匹配后面有空格的字符串。如果要匹配后面有任意空格的,可以用'abc%'。--所以,总结空格处理:--CHAR列:在储时会去掉插入字符串的尾部空格(然后填充到固定长度),检索时再去掉填充的空格,因此最终结果中不包含尾部空格。--VARCHAR列:储时保留尾部空格(不填充),检索时也保留,但在比较操作(非二进制)中,会忽略尾部空格。因此,选择CHAR还是VARCHAR需要根据实际应用场景来决定。相关问题:§§相关问题§§:1.在MySQL中,CHARVARCHAR的最大长度限制分别是多少?2.当使用多字节字符集(如utf8mb4)时,CHAR(10)VARCHAR(10)分别能储多少个中文字符?3.在什么情况下使用CHAR类型VARCHAR类型性能更好?4.如何设置SQL模式以保留CHAR类型在检索时的尾部空格?</think>### MySQLCHAR VARCHAR 类型有什么区别? #### 核心区别总结 1. **储方式** - `CHAR`:固定长度,储时**填充空格**至定义长度 - `VARCHAR`:可变长度,仅储实际数据 + **长度前缀**(1-2字节) 2. **空间效率** - `CHAR`:浪费空间(短数据时) - `VARCHAR`:节省空间(仅用所需空间) 3. **性能特点** - `CHAR`:读取更快(固定长度,无需计算偏移) - `VARCHAR`:更新可能更慢(长度变化时需重新分配空间) 4. **尾部空格处理** - `CHAR`:检索时**自动移除**尾部空格 - `VARCHAR`:**保留**尾部空格(比较时可能被忽略) --- #### 代码示例与解释 ```sql -- 创建测试表 CREATE TABLE string_demo ( char_col CHAR(10), varchar_col VARCHAR(10) ); -- 插入测试数据 INSERT INTO string_demo VALUES ('abc', 'abc'), -- 短字符串 ('abc ', 'abc '), -- 带尾部空格 ('abcdefghij', 'abcdefghij'); -- 满长度字符串 -- 查询数据(显示实际储效果) SELECT CONCAT('[', char_col, ']') AS char_output, CONCAT('[', varchar_col, ']') AS varchar_output, LENGTH(char_col) AS char_bytes, LENGTH(varchar_col) AS varchar_bytes FROM string_demo; ``` **执行结果:** | char_output | varchar_output | char_bytes | varchar_bytes | |-------------|----------------|------------|---------------| | `[abc]` | `[abc]` | 3 | 3 | | `[abc]` | `[abc ]` | 3 | 5 | <!-- 尾部空格被保留 --> | `[abcdefghij]` | `[abcdefghij]` | 10 | 10 | **关键解释:** 1. **空间占用** - `CHAR(10)` 始终占用 10 字节(单字节字符集) - `VARCHAR(10)` 占用实际长度 + 长度前缀(如 'abc' 占 3+1=4 字节) 2. **空格处理** - `CHAR` 插入 `'abc '` → 储为 `'abc'`(空格被移除) - `VARCHAR` 插入 `'abc '` → 储为 `'abc '`(空格保留) 3. **比较行为** ```sql -- CHAR 比较忽略尾部空格 SELECT * FROM string_demo WHERE char_col = 'abc'; -- 匹配所有行 -- VARCHAR 比较也忽略尾部空格(SQL标准) SELECT * FROM string_demo WHERE varchar_col = 'abc'; -- 匹配前两行 ``` --- #### 使用场景建议 - **用 `CHAR` 当**: - 数据长度绝对固定(如 MD5 哈希值、国家代码) - 需要极致读取性能(如高频查询的标识字段) - **用 `VARCHAR` 当**: - 数据长度变化大(如用户名、地址) - 储空间敏感(大表或文本数据) - 需保留尾部空格(如密码字段) > **临界点提示**:当数据长度变化小于 10% 时,`CHAR` 可能更高效(避免碎片化)。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值