CHAR与VARCHAR详解 char 与varchar
wptr33 2024-12-26 17:07 29 浏览
前言:
前面写过一篇介绍int类型的文章,一直想写一篇介绍字符串字段类型的文章,一直拖着也没思路要怎么下手。最近多关注了下这方面的文章,决定还是把拖了好久的文章了结了吧。本篇文章主要会介绍字符串类型char及varchar的用法及区别。
本文实验环境为MySQL 5.7.23版本,存储引擎为Innodb,sql_mode采用严格模式,字符集是utf8。
▍1.CHAR类型介绍
我们平时使用char类型定义字段时,往往会指定其长度M,即char(M)。其实M指的是字符数,即这个字段最多存储多少个字符,M可不指定,默认为1,范围是[0,255],单个字母、数字、中文等都是占用一个字符。utf8字符集下一个中文字符占用3个字节。下面我们简单测试下:
# 假设以如下建表语句创建测试表 CREATE TABLE `char_tb1` ( `col1` char DEFAULT NULL, `col2` char(5) DEFAULT NULL, `col3` char(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; # 进入数据库查询建表语句如下 发现char(M) M可不指定,默认为1 mysql> show create table char_tb1\G *************************** 1. row *************************** Table: char_tb1 Create Table: CREATE TABLE `char_tb1` ( `col1` char(1) DEFAULT NULL, `col2` char(5) DEFAULT NULL, `col3` char(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) # 插入数据 可以看出M表示保存的最大字符数,字母、数字、中文等都是占用一个字符 mysql> insert into char_tb1 (col1) values ('a'),('1'),('王'),(']'); Query OK, 4 rows affected (0.01 sec) mysql> insert into char_tb1 (col1) values ('aa'),('12'); ERROR 1406 (22001): Data too long for column 'col1' at row 1 mysql> select * from char_tb1; +------+------+------+ | col1 | col2 | col3 | +------+------+------+ | a | NULL | NULL | | 1 | NULL | NULL | | 王 | NULL | NULL | | ] | NULL | NULL | +------+------+------+ 4 rows in set (0.00 sec) mysql> insert into char_tb1 (col2) values ('abcd'),('王-123'),('^*123'),('12'),('一二三四五'); Query OK, 5 rows affected (0.01 sec) mysql> insert into char_tb1 (col2) values ('abcdef'); ERROR 1406 (22001): Data too long for column 'col2' at row 1 mysql> select * from char_tb1; +------+-----------------+------+ | col1 | col2 | col3 | +------+-----------------+------+ | a | NULL | NULL | | 1 | NULL | NULL | | 王 | NULL | NULL | | ] | NULL | NULL | | NULL | abcd | NULL | | NULL | 王-123 | NULL | | NULL | ^*123 | NULL | | NULL | 12 | NULL | | NULL | 一二三四五 | NULL | +------+-----------------+------+ 9 rows in set (0.00 sec) # 下面测试发现M的范围是[0,255] mysql> alter table char_tb1 add column col4 char(0); Query OK, 0 rows affected (0.10 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table char_tb1 add column col5 char(255); Query OK, 0 rows affected (0.11 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table char_tb1 add column col5 char(256); ERROR 1074 (42000): Column length too big for column 'col5' (max = 255); use BLOB or TEXT instead
▍2.VARCHAR类型介绍
同样的,varchar(M)中的的M表示保存的最大字符数,单个字母、数字、中文等都是占用一个字符。varchar可存储的长度范围为0-65535字节,此外,varchar需要使用1或者2个额外字节记录字符串的长度:如果列的最大长度小于或等于255字节,则只使用1个字节表示,否则使用2个字节。对于Innodb引擎,utf8字符集来说,单个中文字符占用3个字节,所以varchar(M)中的M最大不会超过21845,即M的范围是[0,21845),并且M必须指定。另外MySQL规定:单个字段长度不大于65535字节;单行最大限制为65535,这里不包括TEXT、BLOB字段。即单张表中的所有varchar字段定义的长度之和不能大于65535,所以并不是所有varchar(M)字段中的M都可以取到21844,下面我们来验证下:
# 假设以如下建表语句创建测试表 CREATE TABLE `varchar_tb1` ( `col1` varchar(0) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; # 查看建表语句 增加字段 发现M必须指定 mysql> show create table varchar_tb1\G *************************** 1. row *************************** Table: varchar_tb1 Create Table: CREATE TABLE `varchar_tb1` ( `col1` varchar(0) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) mysql> alter table varchar_tb1 add column col2 varchar; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 # 下面测试证明M最大可取到21844 mysql> CREATE TABLE `varchar_tb2` (col1 varchar(21844)); Query OK, 0 rows affected (0.04 sec) mysql> CREATE TABLE `varchar_tb3` (col1 varchar(218445)); ERROR 1074 (42000): Column length too big for column 'col1' (max = 21845); use BLOB or TEXT instead # 下面测试证明单行最大限制为65535字节 mysql> CREATE TABLE `varchar_tb3` (col1 varchar(10)); Query OK, 0 rows affected (0.04 sec) mysql> alter table varchar_tb3 add column col2 varchar(21844); 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> alter table varchar_tb3 add column col2 varchar(21834); 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> alter table varchar_tb3 add column col2 varchar(21833); Query OK, 0 rows affected (0.09 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show create table varchar_tb3\G *************************** 1. row *************************** Table: varchar_tb3 Create Table: CREATE TABLE `varchar_tb3` ( `col1` varchar(10) DEFAULT NULL, `col2` varchar(21833) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec)
▍3.CHAR与VARCHAR比较
CHAR类型是定长的,MySQL总是根据定义的字符串长度分配足够的空间。当保存CHAR值时,在它们的右边填充空格以达到指定的长度,当检索到CHAR值时,尾部的空格被删除掉。
VARCHAR类型用于存储可变长字符串,存储时,如果字符没有达到定义的位数,也不会在后面补空格。但是,由于行是变长的,在UPDATE时可能使行变得比原来更长,这就导致需要做额外的工作。如果一个行占用的空间增长,并且在页内没有更多的空间可以存储,在这种情况下InnoDB需要分裂页来使行可以放进页内,这样会增加碎片。
下面简单总结下CHAR与VARCHAR字段类型的适用场景:
CHAR适合存储很短的字符串,或者所有值都接近同一个长度。例如,CHAR非常适合存储密码的MD5值,因为这是一个定长的值。对于经常变更的数据,CHAR也比VARCHAR更好,因为定长的CHAR类型不容易产生碎片。对于非常短的列,CHAR比VARCHAR在存储空间上也更有效率。例如用CHAR(1)来存储只有Y和N的值,如果采用单字节字符集只需要一个字节,但是VARCHAR(1)却需要两个字节,因为还有一个记录长度的额外字节。
下面这些情况下使用VARCHAR是合适的:字符串很长或者所要存储的字符串长短不一,差别很大;字符串列的最大长度比平均长度大得多;列的更新很少,所以碎片不是问题。
额外说明下,我们在定义字段最大长度时应该按需分配,提前做好预估。特别是对于VARCHAR字段,有人认为反正VARCHAR数据类型是根据实际的需要来分配长度的,还不如给大一点呢。但事实不是这样的,比如现在需要存储一个地址信息,根据评估,只要使用100个字符就可以了,我们可以使用VARCHAR(100)或VARCHAR(200)来存储,虽然它们用来存储90个字符的数据,其存储空间相同,但是对于内存的消耗是不同的。更长的列会消耗更多的内存,因为MySQL通常会分配固定大小的内存块来保存内部值,尤其是使用内存临时表进行排列或者操作时会特别糟糕。所以我们在分配VARCHAR数据类型时仍然不能够太过于慷慨。还是要评估实际需要的长度,然后选择一个最长的字段来设置字符长度。如果为了考虑冗余,可以留10%左右的字符长度。千万不能认为VARCHAR是根据实际长度来分配存储空间,而随意的分配长度,或者说干脆使用最大的字符长度。
总结:
本文分别介绍了CHAR与VARCHAR字段类型的使用方法,并且给出了二者的对比以及适用场景。在实际生产情况,需要具体情况具体分析,合适的才是最好的,希望这篇文章能给到大家参考。
欢迎关注个人公众号『MySQL技术』
相关推荐
- redis的八种使用场景
-
前言:redis是我们工作开发中,经常要打交道的,下面对redis的使用场景做总结介绍也是对redis举报的功能做梳理。缓存Redis最常见的用途是作为缓存,用于加速应用程序的响应速度。...
- 基于Redis的3种分布式ID生成策略
-
在分布式系统设计中,全局唯一ID是一个基础而关键的组件。随着业务规模扩大和系统架构向微服务演进,传统的单机自增ID已无法满足需求。高并发、高可用的分布式ID生成方案成为构建可靠分布式系统的必要条件。R...
- 基于OpenWrt系统路由器的模式切换与网页设计
-
摘要:目前商用WiFi路由器已应用到多个领域,商家通过给用户提供一个稳定免费WiFi热点达到吸引客户、提升服务的目标。传统路由器自带的Luci界面提供了工厂模式的Web界面,用户可通过该界面配置路...
- 这篇文章教你看明白 nginx-ingress 控制器
-
主机nginx一般nginx做主机反向代理(网关)有以下配置...
- 如何用redis实现注册中心
-
一句话总结使用Redis实现注册中心:服务注册...
- 爱可可老师24小时热门分享(2020.5.10)
-
No1.看自己以前写的代码是种什么体验?No2.DooM-chip!国外网友SylvainLefebvre自制的无CPU、无操作码、无指令计数器...No3.我认为CS学位可以更好,如...
- Apportable:拯救程序员,IOS一秒变安卓
-
摘要:还在为了跨平台使用cocos2d-x吗,拯救objc程序员的奇葩来了,ApportableSDK:FreeAndroidsupportforcocos2d-iPhone。App...
- JAVA实现超买超卖方案汇总,那个最适合你,一篇文章彻底讲透
-
以下是几种Java实现超买超卖问题的核心解决方案及代码示例,针对高并发场景下的库存扣减问题:方案一:Redis原子操作+Lua脚本(推荐)//使用Redis+Lua保证原子性publicbo...
- 3月26日更新 快速施法自动施法可独立设置
-
2016年3月26日DOTA2有一个79.6MB的更新主要是针对自动施法和快速施法的调整本来内容不多不少朋友都有自动施法和快速施法的困扰英文更新日志一些视觉BUG修复就不翻译了主要翻译自动施...
- Redis 是如何提供服务的
-
在刚刚接触Redis的时候,最想要知道的是一个’setnameJhon’命令到达Redis服务器的时候,它是如何返回’OK’的?里面命令处理的流程如何,具体细节怎么样?你一定有问过自己...
- lua _G、_VERSION使用
-
到这里我们已经把lua基础库中的函数介绍完了,除了函数外基础库中还有两个常量,一个是_G,另一个是_VERSION。_G是基础库本身,指向自己,这个变量很有意思,可以无限引用自己,最后得到的还是自己,...
- China's top diplomat to chair third China-Pacific Island countries foreign ministers' meeting
-
BEIJING,May21(Xinhua)--ChineseForeignMinisterWangYi,alsoamemberofthePoliticalBureau...
- 移动工作交流工具Lua推出Insights数据分析产品
-
Lua是一个适用于各种职业人士的移动交流平台,它在今天推出了一项叫做Insights的全新功能。Insights是一个数据平台,客户可以在上面实时看到员工之间的交流情况,并分析这些情况对公司发展的影响...
- Redis 7新武器:用Redis Stack实现向量搜索的极限压测
-
当传统关系型数据库还在为向量相似度搜索的性能挣扎时,Redis7的RedisStack...
- Nginx/OpenResty详解,Nginx Lua编程,重定向与内部子请求
-
重定向与内部子请求Nginx的rewrite指令不仅可以在Nginx内部的server、location之间进行跳转,还可以进行外部链接的重定向。通过ngx_lua模块的Lua函数除了能实现Nginx...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
面试官:git pull是哪两个指令的组合?
-
git 执行pull错误如何撤销 git pull fail
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)