MySQL中char和varchar的区别

本文探讨了字符和字节的区别,以及在MySQL中char和varchar类型的不同,包括它们在编码、长度单位、存储机制、排序规则和性能影响。建议在多字节字符集中使用varchar,除非确定固定长度且需频繁修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.从字符和字节的区别开始

字节(Byte)是计量单位,表示数据量多少,是计算机信息技术用于计量存储容量的一种计量单位。

字符(Character)计算机中使用的字母、数字、字和符号等,比如'A'、'B'、'$'、'&','中'等。

那么比如: 'A'是占多少个字节的呢?在不同编码中,结果是不一样的。   

  • GBK编码,一个英文字符占一个字节,中文2字节,单字符最大可占用2个字节。
  • UTF-8编码,一个英文字符占一个字节,中文3字节,单字符最大可占用3个字节。
  • utf8mb4编码,一个英文字符占一个字节,中文3字节,单字符最大占4个字节(如emoji表情4字节)。

 

 mysql支持的编码集和默认的编码

 常用的是utf8,而MySQL的“utf8”实际上不是真正的UTF-8。

mysql的“utf8”只支持每个字符最多三个字节,而真正的UTF-8是每个字符最多四个字节

以前版本mysql使用的是utf8,现在官方把以前最多3字节的utf8改成了utf8mb3。而utf8mb4才是完整的utf8(一个字符最多可以占4个字节)。

MySQL在5.5.3之后增加了utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。

所以所有在使用“utf8”的MySQL和MariaDB用户都应该改用“utf8mb4”

说明:后面进行测试的mysql都是上图的版本8.0.36。

2.char和varchar类型对比

这两种都是字符串,char是定长,varchar是变长的。

char(N),varchar(N)中的N表示什么?N个字节还是N个字符?

在version4中长度单位是字节,而在version5及以后版本中是字符

一个中文字占3个字符,表明char(4)中的4表示的是最长是4个字符。

char(N),varchar(N)中的N最大可以是多少?

char

char(N)中的N值最大是255。

对于char类型来说,最多只能存放的字符个数为255,和编码无关,任何编码最大容量都是255。

varchar

而varchar(N)中,很多文章写最大是65536,这是错误的。

MySQL默认最大65535字节,是所有列共享(相加)的,所以varchar的最大值受此限制

表中只有单列字段情况下,varchar一般最多能存放(65535 - 3)个字节,varchar的最大有效长度通过最大行数据长度和使用的字符集来确定,通常的最大长度是65532个字符(当字符串中的字符都只占1个字节时,能达到65532个字符);

为什么是65532个字符?算法如下(有余数时向下取整):

最大长度(字符数) = (行存储最大字节数 - null标识列占用字节数 - 长度标识字节数) / 字符集单字符最大字节数


该列允许是null的时候,null占用字节数为1
长度标识字节数是因为varchar的头部需要存储该列该字符串的长度。长度大于255的时候就需要2字节。

 char,varchar中尾随空格的情况

char类型插入的时候,末尾有空格的话,会去除空格;若插入的字符长度不足默认用空格填满,
检索和获取时会自动去除。

varchar类型插入的时候,末尾有空格的话,不会去除空格。

用concat函数来测试,char类型的进行concat的话,是没有空格,而varchar是有空格的。

也通过select....where...来进行查找。

排序规则collate对char,varchar中尾随空格的影响

上述情况都是发生在我们默认的collate(排序规则)。

排序规则是由使用的编码集来确定的,而我们使用的编码集是utf8mb4,而其默认的collate是utf8mb4_0900_ai_ci。

排序规则以 _ci 结尾,表示不区分大小写(Case Insentive),_cs 表示大小写敏感,_bin 表示通过存储字符的二进制进行比较。

我们先来看看PAD SPACE与NO PAD的具体意义:

  • PAD SPACE:在排序和比较运算中,忽略字符串尾部空格。

  • NO PAD:在排序和比较运算中,字符串尾部空格当成普通字符,不能忽略。

 我们把callate修改成PAD SPACE模式测试下:

name字段的callate修改成utf8mb4_bin,其Pad_attribute是PAD SPACE。

 没有特别情况,我们一般是使用默认情况,就记住这个排序规则。

3.char和varchar在innodb引擎层的存储

Innodb存储引擎支持多种行格式(REDUNDANT、COMPACT、DYNAMIC、COMPRESSED),不同行格式存储方式存在差异。这里是基于默认行格式DYNAMIC。

 varchar

 在表test_varchar插入以下数据(单字节的字母和多字节的中文)。

mysql> show create table test_varchar\G;
*************************** 1. row ***************************
       Table: test_varchar
Create Table: CREATE TABLE `test_varchar` (
  `id` int NOT NULL,
  `code` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci


mysql> insert into test_varcahr values(1,'aaaaa'),(2,'hellohello'),(3,'我我我我我我');

 然后到/var/lib/mysql目录位置,之后找到使用的该数据库,然后在该数据库找到使用的表test_varchar。

之后使用命令 hexdump -C test_varchar.ibd

红框内的05和0a和12(十进制就是18)分别表示的是对应字符串的长度(字节数)5,10,18。绿色下划线部分为实际存储的数据aaaaa和hello,'我'的十六进制是E68891。(可以在mysql中 select hex('我');查看)。

说明varchar类型对于单字节编码、多字节编码,都是存储了字符长度+实际的字符。

char

在表test_char插入以下数据(6字节,30字节,10字节)

mysql> show create table test_char\G;
*************************** 1. row ***************************
       Table: test_char
Create Table: CREATE TABLE `test_char` (
  `id` int NOT NULL,
  `code` char(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

mysql> insert into test_char values(1,'我aaa'),(2,'我我我我我我我我我我'),(3,'bbbbbbbbbb');

 code字段是char(20),表明该字段最多可以存储20*4=80字节大小的数据。

 可以看到,红色的是数据大小,14,1e,14。表明char类型的,innodb也是保存了字符长度的。而长度不够80字节的,末尾是用0x20(即是空格)来插入。

而这也有个情况,不是每次都是开辟80字节的空间来存储的。从这个实验来看,是这样:要是插入的大小不足设置的数值20(这里char(N)的N是20),就只开辟20字节的空间存储,超过20字节了,就开辟实际大小的空间来存储(1e就是十进制30)。

char和varchar的存储总结

  1. 都是存储长度大小和实际数据。
  2. 对于CHAR(N)字段,如果实际存储数据小于N字节,会填充空格到N个字节。

网上说的对于innodb引擎,建议使用varchar就是这个原因吧。

4.用char还是varchar

 经过上面的分析,我们可知,UTF8MB4 字符集 1 个字符最大存储 4 个字节。所以从底层存储看,在多字节字符集下,CHAR 和 VARCHAR 底层的实现完全相同,都是变长存储

所以建议大部分可以使用varchar

但是要是就确定是这么多字节的,那当然是使用char的。

还有种情况:知道该字段的最大长度,并且该字段需要频繁修改的。比如使用char(50),则插入记录后就分配了50个字节,后续修改不会造成页分裂、页空隙等情况;而varchar(50)由于没有提前分配存储空间,后续修改时可能出现页分裂,进而导致性能下降。

内容概要:本文档详细介绍了在三台CentOS 7服务器(IP地址分别为192.168.0.157、192.168.0.158和192.168.0.159)上安装和配置Hadoop、Flink及其他大数据组件(如Hive、MySQL、Sqoop、Kafka、Zookeeper、HBase、Spark、Scala)的具体步骤。首先,文档说明了环境准备,包括配置主机名映射、SSH免密登录、JDK安装等。接着,详细描述了Hadoop集群的安装配置,包括SSH免密登录、JDK配置、Hadoop环境变量设置、HDFS和YARN配置文件修改、集群启动与测试。随后,依次介绍了MySQL、Hive、Sqoop、Kafka、Zookeeper、HBase、Spark、Scala和Flink的安装配置过程,包括解压、环境变量配置、配置文件修改、服务启动等关键步骤。最后,文档提供了每个组件的基本测试方法,确保安装成功。 适合人群:具备一定Linux基础和大数据组件基础知识的运维人员、大数据开发工程师以及系统管理员。 使用场景及目标:①为大数据平台建提供详细的安装指南,确保各组件能够顺利安装和配置;②帮助技术人员快速掌握Hadoop、Flink等大数据组件的安装与配置,提升工作效率;③适用于企业级大数据平台的建与维护,确保集群稳定运行。 其他说明:本文档不仅提供了详细的安装步骤,还涵盖了常见的配置项解释和故障排查建议。建议读者在安装过程中仔细阅读每一步骤,并根据实际情况调整配置参数。此外,文档中的命令和配置文件路径均为示例,实际操作时需根据具体环境进行适当修改。
在无线通信领域,天线阵列设计对于信号传播方向和覆盖范围的优化至关重要。本题要求设计一个广播电台的天线布局,形成特定的水平面波瓣图,即在东北方向实现最大辐射强度,在正东到正北的90°范围内辐射衰减最小且无零点;而在其余270°范围内允许出现零点,且正西和西南方向必须为零。为此,设计了一个由4个铅垂铁塔组成的阵列,各铁塔上的电流幅度相等,相位关系可自由调整,几何布置和间距不受限制。设计过程如下: 第一步:构建初级波瓣图 选取南北方向上的两个点源,间距为0.2λ(λ为电磁波波长),形成一个端射阵。通过调整相位差,使正南方向的辐射为零,计算得到初始相位差δ=252°。为了满足西南方向零辐射的要求,整体相位再偏移45°,得到初级波瓣图的表达式为E1=cos(36°cos(φ+45°)+126°)。 第二步:构建次级波瓣图 再选取一个点源位于正北方向,另一个点源位于西南方向,间距为0.4λ。调整相位差使西南方向的辐射为零,计算得到相位差δ=280°。同样整体偏移45°,得到次级波瓣图的表达式为E2=cos(72°cos(φ+45°)+140°)。 最终组合: 将初级波瓣图E1和次级波瓣图E2相乘,得到总阵的波瓣图E=E1×E2=cos(36°cos(φ+45°)+126°)×cos(72°cos(φ+45°)+140°)。通过编程实现计算并绘制波瓣图,可以看到三个阶段的波瓣图分别对应初级波瓣、次级波瓣和总波瓣,最终得到满足广播电台需求的总波瓣图。实验代码使用MATLAB编写,利用polar函数在极坐标下绘制波瓣图,并通过subplot分块显示不同阶段的波瓣图。这种设计方法体现了天线阵列设计的基本原理,即通过调整天线间的相对位置和相位关系,控制电磁波的辐射方向和强度,以满足特定的覆盖需求。这种设计在雷达、卫星通信和移动通信基站等无线通信系统中得到了广泛应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值