CHAR 和 VARCHAR 存取的差别

栏目: 数据库 · 发布时间: 4年前

内容简介:你真的知道CHAR和VARCHAR类型在存储和读取时的区别吗?还是先抛几条结论吧:1、

导读

你真的知道CHAR和VARCHAR类型在存储和读取时的区别吗?

还是先抛几条结论吧:

1、 存储的时候,CHAR总是会补足空格后再存储 ,不管用户插入数据时尾部有没有包含空格。

2、 存储的时候,VARCHAR不会先补足空格后再存储 ,但如果是用户在插入时特地加了空格那就会如实存储,而不会给删除。

3、 读取数据时,CHAR总是会删除尾部空格 (哪怕是写入时包含空格)。

4、 读取数据时,VARCHAR总是如实取出之前存入的值 (如果存储时尾部包含空格,就会继续保留着,不会像CHAR那样删除尾部空格)。

下面是测试验证过程。

1、测试CHAR类型

表结构:

CREATE TABLE `tchar` (
  `id` int(10) unsigned NOT NULL DEFAULT '0',
  `c1` char(20) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

插入几条记录:

insert into tchar values (1, concat('a', repeat(' ',19)));
insert into tchar values (2, concat(' ', repeat('a',19)));
insert into tchar values (3, 'a');
insert into tchar values (4, ' ');
insert into tchar values (5, '');

查看存储结构:

(1) INFIMUM record offset:99 heapno:0 ...
(2) SUPREMUM record offset:112 heapno:1 ...
(3) normal record offset:126 heapno:2 ... <- id=1
(4) normal record offset:169 heapno:3 ... <- id=2
(5) normal record offset:212 heapno:4 ... <- id=3
(6) normal record offset:255 heapno:5 ... <- id=4
(7) normal record offset:298 heapno:6 ... <- id=5

看到这坨东西有点懵是不是,还记得我给你们安利过的一个 工具 不,看这里: innblock | InnoDB page观察利器。

可以看到,无论我们存储多长的字符串进去,每条记录实际都是占用43(169-126=43)字节。由此结论1成立。

简单说下,43字节的由来:

DB_TRX_ID, 6字节。

DB_ROLL_PTR, 7字节。

id, int, 4字节。

c1, char(20), 20字节;因为是CHAR类型,还需要额外1字节。

每条记录总是需要额外5字节头信息(row header)。

这样总的加起来就是43字节了。

再看下读取tvarchar表的结果:

select id,concat('000',c1,'$$$'),length(c1) from tchar ;
+----+----------------------------+------------+
| id | concat('000',c1,'$$$')     | length(c1) |
+----+----------------------------+------------+
|  1 | 000a$$$                    |          1 | <- 删除尾部空格
|  2 | 000 aaaaaaaaaaaaaaaaaaa$$$ |         20 |
|  3 | 000a$$$                    |          1 |
|  4 | 000$$$                     |          0 | <- 删除尾部空格,结果和id=5一样
|  5 | 000$$$                     |          0 |
+----+----------------------------+------------+

2、测试CHAR类型

表结构:

CREATE TABLE `tvarchar` (
  `id` int(10) unsigned NOT NULL DEFAULT '0',
  `c1` varchar(20) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

插入几条记录:

insert into tvarchar values (1, concat('a', repeat(' ',19)));
insert into tvarchar values (2, concat(' ', repeat('a',19)));
insert into tvarchar values (3, 'a');
insert into tvarchar values (4, ' ');
insert into tvarchar values (5, '');
insert into tvarchar values (6, '');

查看存储结构:

(1) INFIMUM record offset:99 heapno:0 ...
(2) SUPREMUM record offset:112 heapno:1 ...
(3) normal record offset:126 heapno:2 ... <- id=1
(4) normal record offset:169 heapno:3 ... <- id=2
(5) normal record offset:212 heapno:4 ... <- id=3
(6) normal record offset:236 heapno:5 ... <- id=4
(7) normal record offset:260 heapno:6 ... <- id=5
(8) normal record offset:283 heapno:7 ... <- id=6

可以看到,几条记录的字节数分别是:43、43、24、24、23、23(最后一条记录和id=5那条记录一样)。

对上面这个结果有点诧异是不是,尤其是id=1的记录(插入的是'a...后面19个空格'),居然也要消耗43字节,这就佐证了上面的结论2。

同样的,id=3和id=4这两条记录都是占用24字节,而id=5和id=6这两条记录都是占用23字节(没有额外存储字符串的字节数,只有id列4个字节)。

再看下读取tvarchar表的结果:

select id,concat('000',c1,'$$$'),length(c1) from tvarchar;
+----+----------------------------+------------+
| id | concat('000',c1,'$$$')     | length(c1) |
+----+----------------------------+------------+
|  1 | 000a                   $$$ |         20 | <- 读取结果中没有删除尾部的空格
|  2 | 000 aaaaaaaaaaaaaaaaaaa$$$ |         20 |
|  3 | 000a$$$                    |          1 |
|  4 | 000 $$$                    |          1 | <- 读取结果中没有删除此空格
|  5 | 000$$$                     |          0 |
|  6 | 000$$$                     |          0 |
+----+----------------------------+------------+

总的来说,可以总结成两条结论:

1、从读取的结果来看,CHAR类型列看起来像是在存储时把空格给吃了,但实际上只是在读取时才给吃了(显示层面上把空格删除了)。

2、从读取的结果来看,VARCHAR类型列看起来像是反倒保留了多余的空格,实际上也是只在读取时才恢复这些空格(但实际物理存储时还是会删掉这些空格)。

最后,来看下文档里怎么说的:

When CHAR values are stored, they are right-padded with spaces to the specified length. 简言之,CHAR列在存储时尾部加空格补齐长度。
When CHAR values are retrieved, trailing spaces are removed unless the PAD_CHAR_TO_FULL_LENGTH SQL mode is enabled. 简言之,CHAR列在读取时会去掉尾部空格,除非设置sql_mode值PAD_CHAR_TO_FULL_LENGTH=1。
VARCHAR values are not padded when they are stored. 简言之,存VARCHAR时尾部不加空格。
Trailing spaces are retained when values are stored and retrieved, in conformance with standard SQL. 简言之,读取VARCHAR时会显示空格。

以上测试使用的版本及环境:

mysql> select version()\G
...
version(): 8.0.15

mysql> select @@sql_mode\G
...
@@sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

参考文档

更多 MySQL 有趣冷知识,还可以看这里哦

CHAR 和 VARCHAR 存取的差别


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Four

The Four

Scott Galloway / Portfolio / 2017-10-3 / USD 28.00

NEW YORK TIMES BESTSELLER USA TODAY BESTSELLER Amazon, Apple, Facebook, and Google are the four most influential companies on the planet. Just about everyone thinks they know how they got there.......一起来看看 《The Four》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码