前两话细聊了日期时间类型和数值类型,本篇文章来看下最后一个大的数据类型:字符串类型。
字符串类型是实际工程中遇到最多的一种类型,MySQL提供了丰富的字符串类型,我们来总览看下:
类型 | 最大长度 | 存储空间要求 | 含义 |
---|---|---|---|
CHAR(M) | M个字符 | M×W个字节 | 固定长度的字符串 |
VARCHAR(M) | M个字符 | L+1 或 L+2 个字节 | 可变长度的字符串 |
TINYTEXT | 2⁸-1 个字节 | L+1个字节 | 非常小型的字符串 |
TEXT | 2¹⁶-1 个字节 | L+2 个字节 | 小型的字符串 |
MEDIUMTEXT | 2²⁴-1 个字节 | L+3个字节 | 中等大小的字符串 |
LONGTEXT | 2³²-1 个字节 | L+4个字节 | 大型的字符串 |
其中M代表该数据类型最多能存储的字符数量,L代表我们实际向该类型的属性中存储的字符串在特定字符集下所占的字节数,W代表在该特定字符集下,编码一个字符最多需要的字节数。
目前还是有点懵,没关系,我们下面细细道来,本文的整体脉络如下:
一、CHAR(M)
-
【说明1】CHAR(M)中的M代表该类型最多可以存储的字符数量,注意,是字符数量,不是字节数量。其中M的取值范围是0~255。 -
【说明2】填一个汉字算一个字符,填一个数字或字母也算是一个字符,而不用关心一个汉字需要多少个字节来存储。 -
【说明3】如果省略掉M的值,那它的默认值就是1,也就是说CHAR和CHAR(1)是一个意思。 -
【说明4】CHAR(0)是一种特别的类型,它只能存储空字符串”或者NULL值。
-
对于采用ascii字符集的CHAR(5)类型来说,ascii字符集编码一个字符最多需要1个字节,也就是M=5、W=1,所以这种情况下该类型占用的存储空间大小就是5×1 = 5个字节。 -
对于采用gbk字符集的CHAR(5)类型来说,gbk字符集编码一个字符最多需要2个字节,也就是M=5、W=2,所以这种情况下该类型占用的存储空间大小就是5×2 = 10个字节。 -
对于采用utf8字符集的CHAR(5)类型来说,utf8字符集编码一个字符最多需要3个字节,也就是M=5、W=3,所以这种情况下该类型占用的存储空间大小就是5×3 = 15个字节。
-
【说明5】如果保存时,数据的实际长度比CHAR类型声明的长度小,则会在右侧填充空格以达到指定的长度。这也就是说:一旦你确定了CHAR(M)类型的M的值,如果M的值很大,而你实际存储的字符串占用字节数又很少,会造成存储空间的浪费。
mysql> CREATE TABLE test_char1( c1 CHAR(0) , c2 CHAR, c3 CHAR(5) );
Query OK, 0 rows affected (0.03 sec)
mysql> desc test_char1;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| c1 | char(0) | YES | | NULL | |
| c2 | char(1) | YES | | NULL | |
| c3 | char(5) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
3 rows in set (0.01 sec)
可以看到,CHAR和CHAR(1)是一个意思,验证了【说明3】的说法;我们对c1赋值测试,验证了【说明4】的说法:
mysql> insert into test_char1(c1) value('aaa');
ERROR 1406 (22001): Data too long for column 'c1' at row 1
mysql> insert into test_char1(c1) value('a');
ERROR 1406 (22001): Data too long for column 'c1' at row 1
mysql> insert into test_char1(c1) value('');
Query OK, 1 row affected (0.00 sec)
mysql> select * from test_char1;
+------+------+------+
| c1 | c2 | c3 |
+------+------+------+
| | NULL | NULL |
+------+------+------+
1 row in set (0.00 sec)
结合【说明1】,由于c2长度为1,那么就只能赋值一个字符,两个就会超出范围报错:
mysql> insert into test_char1(c2) value('aa');
ERROR 1406 (22001): Data too long for column 'c2' at row 1
mysql> insert into test_char1(c2) value('你好');
ERROR 1406 (22001): Data too long for column 'c2' at row 1
mysql> insert into test_char1(c2) value('好');
Query OK, 1 row affected (0.00 sec)
mysql> select * from test_char1;
+------+------+------+
| c1 | c2 | c3 |
+------+------+------+
| NULL | 好 | NULL |
+------+------+------+
2 rows in set (0.00 sec)
我们对c3字段赋值,由于它的长度是5,那么最多可以放5个字符:
mysql> update test_char1 set c3='你好哇哇';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select char_length(c3) from test_char1;
+-----------------+
| char_length(c3) |
+-----------------+
| 4 |
+-----------------+
1 row in set (0.00 sec)
mysql> update test_char1 set c3='你好哇哇哇哇';
ERROR 1406 (22001): Data too long for column 'c3' at row 1
二、VARCHAR(M)
一般情况下,字符串是长短不一的,如果使用CHAR会造成很大的空间浪费,VARCHAR(M)正是为了解决这个问题而生。
VARCHAR(M)中的M也是代表该类型最多可以存储的字符数量,最大允许多少呢?
mysql> CREATE TABLE test_varchar( NAME VARCHAR(65535) );
ERROR 1074 (42000): Column length too big for column 'NAME' (max = 21845); use BLOB or TEXT instead
mysql> CREATE TABLE `test_varchar2` ( `NAME` varchar(65535) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ERROR 1074 (42000): Column length too big for column 'NAME' (max = 16383); use BLOB or TEXT instead
-
utf8mb3:“阉割”过的UTF-8字符集,只使用1-3字节表示字符。 -
utf8mb4:“正宗”的UTF-8字符集,使用1-4字节表示字符。
-
真正的字符串内容:假设真正的字符串在特定字符集编码后占用的字节数为L。 -
占用字节数(假设VARCHAR(M)类型采用的字符集编码一个字符最多需要W个字节,那么): -
当M×W < 256时,只需要一个字节来表示占用的字节数。 -
当M×W >= 256且M×W < 65536时,需要两个字节来表示占用的字节数。
所以我们说VARCHAR(M)是一种可变长度的字符串类型。
三、VARCHAR和CHAR类型
VARCHAR相对于CHAR类型,其实还有一个有趣的差异:MySQL检索CHAR类型的数据时,CHAR类型的字段会去除尾部的空格;检索VARCHAR类型的字段数据时,会保留数据尾部的空格。
举个简单的例子就可以很容易地理解这个区别了。
mysql> CREATE TABLE test_varchar3( c CHAR(4) , v VARCHAR(4) );
Query OK, 0 rows affected (0.03 sec)
mysql> desc test_varchar3;
+-------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| c | char(4) | YES | | NULL | |
| v | varchar(4) | YES | | NULL | |
+-------+------------+------+-----+---------+-------+
2 rows in set (0.01 sec)
创建了一张表,定义了c char(4) 和 v varchar(4)两个字段,同时插入字符串“ab ”,注意ab后面有两个空格:
mysql> insert into test_varchar3 values('ab ','ab ');
Query OK, 1 row affected (0.00 sec)
mysql> select * from test_varchar3;
+------+------+
| c | v |
+------+------+
| ab | ab |
+------+------+
1 row in set (0.00 sec)
mysql> select length(c),length(v) from test_varchar3;
+-----------+-----------+
| length(c) | length(v) |
+-----------+-----------+
| 2 | 4 |
+-----------+-----------+
1 row in set (0.00 sec)
可以发现,c的长度只有2,而v的长度还是4,我们给每个字段后面追加一个“+”号可以看得比较明显:
mysql> select concat(c,'+'),concat(v,'+') from test_varchar3;
+---------------+---------------+
| concat(c,'+') | concat(v,'+') |
+---------------+---------------+
| ab+ | ab + |
+---------------+---------------+
1 row in set (0.01 sec)
concat()函数是mysql中内置的函数,用来做字符串拼接或多个字段的拼接输出,虽然没有系统介绍过,但是相信很容易可以理解这里的用法。
-
1、char属于固定长度的字符类型,varchar属于可变长度的字符类型。 -
2、他们的存储方式不太一样,varchar中还需要额外1个字节或2个字节的长度来保存后面实际字符串的占用的字节数,而char占用的字节数已经在初始定义的时候已经固定下来了。 -
3、他们的检索方式也有点不同,检索时char会删除尾部的空格,varchar则会保留尾部的空格。
四、各种TEXT类型
-
因为TINYTEXT最多可以存储2⁸-1个字节,所以内容占用的字节长度用1个字节就可以表示。 -
TEXT最多可以存储2¹⁶-1个字节,所以内容占用的字节长度用2个字节就可以表示。 -
MEDIUMTEXT最多可以存储2²⁴-1个字节,所以内容占用的字节长度用3个字节就可以表示。 -
LONGTEXT最多可以存储2³²-1个字节,所以内容占用的字节长度用4个字节就可以表示。
varchar类型和text类型的比较是比较有说头的,牵涉到更加具体的存储模式,我们日后在学习底层原理的时候我们再来对这两者做个深入比较。
MySQL其实还有一些比较小众的类型,比如ENUM类型、SET类型以及各种二进制类型,不过这些在实际生产系统中很少见到,因此在这里不展开赘述,如果哪一天你的系统中用到了这些类型,也请考虑下为什么使用,是不是换成其他类型或存储方式更加合适。
五、总结
-
CHAR(M)和VARCHAR(M)两种类型分别有什么特点?有什么区别? -
字符串类型在不同的字符集下占用的空间是如何计算的? -
TEXT类型有哪些?在什么场景下使用,跟varchar类型的区别感兴趣可以提前去了解下。
原文始发于微信公众号(幕后哈土奇):07|第七话:基础篇-MySQL数据类型之字符串类型
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/112887.html