MySQL数据类型(二)

发布于 2022-07-03  1.9k 次阅读


#1. 字符串类型

字符串类型有两个CHAR,VARCHAR

字符串类型 值的长度 长度范围 占用的存储空间
CHAR(M) M 0<=M<=255 M个字节
VARCHAR(M) M 0<=M<=65535 M+1个字节

#1.1 CHAR类型

  • CHAR(M)类型一般需要预先定义字符串长度,如果不指定(M),则表示长度默认是1个字节

  • 如果保存是,数据的实际长度比CHAR类型声明的长度小,则会在右侧空格填充以达到指定长度,当MySQL检索CHAR类型的数据时,CHAR类型的字段会去除尾部的空格

  • 定义CHAR类型字段时,声明的字段长度即为CHAR类型字段的所占存储空间的这数

例:

mysql> CREATE TABLE chartest(
    -> c1 CHAR,
    -> c2 CHAR(5));
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO chartest VALUES("1","wql"),("2","wql  ");
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

//插入的空格被清除
mysql> SELECT * FROM chartest;
+------+------+
| c1   | c2   |
+------+------+
| 1    | wql  |
| 2    | wql  |
+------+------+
2 rows in set (0.00 sec)

CHAR类型中一个汉字占用两长度

#1.2 VARCHAR类型

  • VARCHAR(M)定义时,必须指定长度M,否则报错

  • MySQL4.0版本以下,VARCHAR(20):指的是20个子节,如果存放UTF8汉字时,只能存6个(每一个汉字3字节)

  • 在MySQL5.0以上版本,VARCHAR(20):指的是20个字符

  • 检索VARCHAR类型的字段数据时,会保留数据尾部的空格,VARCHAR类型的字段所占的存储空间为字符串实际长度加

例:

mysql> CREATE TABLE varchartest(
    -> c2 VARCHAR(5));
Query OK, 0 rows affected (0.00 sec)


mysql> INSERT INTO chartest VALUES("空想家");
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM chartest;
+------+
| c2   |
+------+
| 空想家|
+------+
2 rows in set (0.00 sec)

#1.3 CHAR和VARCHAR的选择

类型 特点 空间上 时间上 适用场景
CHAR(M) 固定长度 浪费存储空间 效率高 存储不大,速度要求高
VARCHAR(M) 可变长度 节省存储空间 效率低 非CHAR的情况

场景1:存储很短。比如门牌号码101,201……这样很短的信息应该用CHAR,因为VARCHAR还要占byte用于存储信息长度
场景2:固定长度。比如UUID作为主键,那用CHAR应该更合适,因为他固定长度,VARCHAR动态根据长度的特性就不适用
场景3:十分频繁改变的colu mn。因为varchar每次存储都要有额外的计算,得到长度等工作,如果一个非常频繁改变的,那就要有很多的精力用于计算,而对于char就不需要

具体存储引擎的情况:

  • MYISAM数据存储引擎:MyISAM数据表,最好使用固定长度(CHAR)的数据列代替可变长度(VARCHAR)的数据列。这样使得整个表的静态化,从而使数据检索更快,用空间换时间

  • InnoDB存储引擎:建议使用VARCHAR类型。因为对于InnoDB数据表,内部的行存储格式并没有区分固定长度和可变长度(所有数据行都使用指向数据列值的头指针),而且主要影响性能的因素是数据行使用的存储总量,由于char平均占用的空间多于varchar,所以除了简短而且固定长度,其他都考虑varchar。这样,对磁盘I/O和数据存储总量比较好

  • MEMORY存储引擎:MEMORY数据表目前都使用固定长度的数据行存储,因此无论使用CHAR或VARCHAR列都没有关系,两者都是作为CHAR类型处理

#2. 文本类型

在MySQL中,TEXT用来保存文本类型的字符串(文本本质上就是长字符),总共包括4种类型,分别为TINYTEXT,TEXT,MEDIUMTEXT和LONGTEXT类型

在向TEXT类型的字段保存和查询数据时,系统自动按照实际长度存储,不需要预先定义长度。这一点和VARCHAR类型相同

文本类型 特点 长度 长度范围 占用的存储空间
TINYTEXT 小文本,可变长度 L 0<= L <=255 L+2个字节
TEXT 文本,可变长度 L 0<= L <=65535 L+2个字节
MEDIUMTEXT 中等文本,可变长度 L 0<= L <= 16777215 L+3个字节
LONGTEXT 大文本,可变长度 L 0 <= L <=4294967295(相当于4G) L+4个字节

注:由于实际存储的长度不确定,MySQL不允许TEXT类型的字段作为主键。遇到这种情况,只能采用CHAR(M)或VARCHAR(M)

例:

mysql> CREATE TABLE texttest(
    -> t1 TINYTEXT,
    -> T2 TEXT,
    -> t3 MEDIUMTEXT);
Query OK, 0 rows affected (0.01 sec)

mysql> DESC texttest;
+-------+------------+------+-----+---------+-------+
| Field | Type       | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| t1    | tinytext   | YES  |     | NULL    |       |
| T2    | text       | YES  |     | NULL    |       |
| t3    | mediumtext | YES  |     | NULL    |       |
+-------+------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> INSERT INTO texttest VALUES("啦啦啦啦啦啦啦啦","啦啦啦啦","啦啦啦啦啦啦啦啦");
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM texttest;
+------------------+----------+------------------+
| t1               | T2       | t3               |
+------------------+----------+------------------+
| 啦啦啦啦啦啦啦啦 | 啦啦啦啦 | 啦啦啦啦啦啦啦啦 |
+------------------+----------+------------------+
1 row in set (0.00 sec)

开发经验:TEXT文本类型,可以存储比较大的文本段,搜索速度比较慢。因此如果不是特别大的内容,建议使用CHAR或VARCHAR来代替,还有TEXT类型不用加默认值(加了也没用),而且text和blob类型的数据删除后容易导致"空洞",使得文件碎片比较多,所以频繁使用的表不建议包含TEXT类型字段,建议单独分离出去,单独用一张表

#3. 枚举类型和集合类型

#3.1 枚举类型

ENUM类型也叫枚举类型,ENUM类型的取值范围需要在定义字段时进行指定,设置字段值时,ENU类型只允许从成员中选取单个值,不能一次选取多个值

其所需的存储空间由定义ENUM类型时指定的成员个数决定其所需的存储空间由定义ENUM类型时指定的成员个数决定

枚举类型 长度 长度范围占用的存储空间 ENUM
EMUN L 1<=L<=65535 1或2个字节
  • 当ENUM类型包含1~255个成员时,需要1个字节的存储空间
  • 当ENUM类型包含256 ~ 65535个成员时,需要2个字节的存储空间
  • ENUM类型的成员个数上限为65535

例:

mysql> CREATE TABLE enumtest(
    -> e1 ENUM('春季','夏季','秋季','冬季'));
Query OK, 0 rows affected (0.00 sec)

mysql> DESC enumtest;
+-------+-----------------------------------+------+-----+---------+-------+
| Field | Type                              | Null | Key | Default | Extra |
+-------+-----------------------------------+------+-----+---------+-------+
| e1    | enum('春季','夏季','秋季','冬季') | YES  |     | NULL    |       |
+-------+-----------------------------------+------+-----+---------+-------+
1 row in set (0.00 sec)

mysql> INSERT INTO enumtest VALUES('夏季');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM enumtest;
+------+
| e1   |
+------+
| 夏季 |
+------+
1 row in set (0.00 sec)

mysql> INSERT INTO enumtest VALLUES("夏季,秋季");
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 'VALLUES("夏季,秋季")' at line 1

注:
- 在插入时忽然大小写
- 可以为空

#3.2 SET集合类型

SET表示一个字符串对象,可以包含0个或多个成员,当成员个数的上限威64,设置字段时,可以取值范围内的0个或多个值

当SET类型包含的成员个数不同时,其所占用的存储空间也是不同的

成员个数范围(L为实际成员个数) 占用的存储空间
1<= L <=8 1个字节
9<= L <=16 2个字节
17<= L <=24 3个字节
25<= L <=32 4个字节
33<= L <=64 8个字节

SET类型在存储数据时,成员个数越多,其占用的存储空间就越大

注:SET类型在选取成员时,可以一次选择多个成员,这一点与ENUM类型不同

例:

mysql> CREATE TABLE settest(
    -> s1 SET("夏季","秋季","冬季","春季"));
Query OK, 0 rows affected (0.00 sec)

mysql> DESC settest;
+-------+----------------------------------+------+-----+---------+-------+
| Field | Type                             | Null | Key | Default | Extra |
+-------+----------------------------------+------+-----+---------+-------+
| s1    | set('夏季','秋季','冬季','春季') | YES  |     | NULL    |       |
+-------+----------------------------------+------+-----+---------+-------+
1 row in set (0.00 sec)

mysql> INSERT INTO settest VALUES("夏季,秋季");
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM settest;
+-----------+
| s1        |
+-----------+
| 夏季,秋季 |
+-----------+
1 row in set (0.00 sec)

#4. 二进制字符串类型

MySQL中的二进制字符串类主要存储一些二进制数据,比如存储图片,音频和视频等二进制数据
MySQL中支持的二进制字符串类型主要包括BINARY,VARBINARY,BLOB,MEDIUMBLOB和LONGBLOB类型

#4.1BINARY和VARBINARY

BIINARY和VARBINARY类似于CHAR和VARCHAR,只是它们存储的是二进制字符串:
- BINARY(M)的概念:固定长度的二进制字符串,M表示最多能存储的字节数,取值范围是0~255个字符。如果未指定(M),表示只能存储1个字节。例如:BINARY(8)表示最多存储8字节,如果字段值不足(M)个字节,将在右边填充'\0'以补齐长度

  • VARCHAR(M)概念:可变长度的二进制字符串,M表示最多能存储的字节数,总字节数不能超过行的字节长度限制65535,另外还要考虑额外字节开销,VARCHAR类型的数据除了存储数据本身外,还需要1或2字节来存储数据的字节数。VARCHAR类型必须指定(M)
二进制字符串类型 特点 值的长度 占用空间
BINARY(M) 固定长度 M(0 <=M<=255) M个字节
VARBINARY 可变长度 M(0 <=M<=65535) M+1个字节

例:

mysql> CREATE TABLE binarytest(
    -> b1 BINARY,
    -> b2 BINARY(5),
    -> B4 VARBINARY(5));
Query OK, 0 rows affected (0.00 sec)

mysql> DESC binarytest;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| b1    | binary(1)    | YES  |     | NULL    |       |
| b2    | binary(5)    | YES  |     | NULL    |       |
| B4    | varbinary(5) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> INSERT INTO binarytest VALUES('a','asb','daswq');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM binarytest;
+------+-------+-------+
| b1   | b2    | B4    |
+------+-------+-------+
| a    | asb   | daswq |
+------+-------+-------+
1 row in set (0.00 sec)

#4.2 BLOB类型

BLOB是一个二进制的大对象,可以容纳可变数量的数量

MySQL中的BLOB类型包括TINYBLOB,BLOB,MEDIUMBLOB和LONGBLO等4种类型,它们可以然值的最大长度不同,可以存储一个大的二进制的大对象,比如图片,音频和视频等

注:在开发种指向图片等静态资源是不会存在Mysql中的,一般存在分布式文件系统中(如:MinIO,FastDfs),现在有专门的SSO对象存储服务器

二进制字符串类型 值的长度 长度范围 占用空间
TINYBLOB L 0<=L<=255 L+1个字节
BLOB L 0<=L<=65535(相当于64k) L+2个字节
MEDIUMBLOB L 0<=L<=16777215(相当于1MB) L+3个字节
LONGBLOB L 0<=L<=4294967295(相当于4G) L+4个字节

TEXT和BLOB的使用注意事项:在使用text和blob字段类型时需要注意以下几点,以便提供数据库的性能

  1. BLOB和TEXT值有自己本身的问题,特别是在执行大量的删除或更新操作时。删除这种值会在数据表中产生很大的"空洞",以后插入填入这些 '空洞' 的记录可能长度不同。为了提供性能,建议定期使用OPTIMIZE TABLE功能对这类表进行碎片整理
  2. 如果需要对大文本字段进行模糊查询,MySQL提供了前缀索引,但是仍然要在不必要的时候避免检索大型的BLOB或TEXT值。例如:SELECT *查询就不是一个很好的做法,除非你能确定作为约束条件的WHERE子句找到所需要的数据行
  3. 在项目中建议大型的BLOB和TEXT分离到单独的表中。在某些环境中,如果把这些数据列移动到第二张数据表中,可以在原数据表定义固定长度的数据格式。这会减少主表的碎片

#5. JSON类型

JSON (JavaScript Object Notation)是一种轻量级的数据交换格式。简洁和清晰的层次结构使得JSON成为理想的数据交换语言。它易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

JSON可以将JavaScript对象中表示的一组数据转换为字符串,然后就可以在网络或者程序之间轻松地传递这个字符串,并在需要的时候将它还原为各编程语言所支持的数据格式。

在MySQL 5.7中支持JSON数据类型。在MysQL 8.x版本中,JSON类型提供了可以进行自动验证的JSON文档和优化的存储结构,使得在MySQL中存储和读取JSON类型的数据更加方便和高效。创建数据表,表中包含一个JSON类型的字段js。

例:

mysql> CREATE TABLE jsontest(
    -> j1 JSON);
Query OK, 0 rows affected (0.00 sec)

mysql> DESC jsontest;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| j1    | json | YES  |     | NULL    |       |
+-------+------+------+-----+---------+-------+
1 row in set (0.00 sec)

mysql> INSERT INTO jsontest(j1) VALUES('{"name":"WQL-KXJ","age":"18","address":{"provider":"chansha","ll":"ll"}}');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM jsontest;
+----------------------------------------------------------------------------------+
| j1                                                                               |
+----------------------------------------------------------------------------------+
| {"age": "18", "name": "WQL-KXJ", "address": {"ll": "ll", "provider": "chansha"}} |
+----------------------------------------------------------------------------------+
1 row in set (0.00 sec)

//精准获取
mysql> SELECT j1->'$.name' AS name  FROM jsontest;
+-----------+
| name      |
+-----------+
| "WQL-KXJ" |
+-----------+
1 row in set (0.00 sec)

#6. 类型选择建议

在定义数据类型时,如果确定是整数就选择INT,如果是小数一旦要使用DECIMAL(M,D),如果是日期和时间类型就选择DATETIME

这样做的好处,首先确保你的系统不会因为数据类型定义出错。不过,凡事都是两面的,可靠性好,并不意味着高效,,比如TEXT虽然使用方便,但是效率不如CHAR()和VARCHAR()

阿里巴巴数据库规范:
1. 【强制】当确定整数类型是正数时,一定要加UNSIGNED无符号数
2. 【强制】小数类型为DECIMAL,禁止使用FLOAT和DOUBLE

在存储时FLOAT和DOUBLE存在精度损失的问题,很可能在比较值的时候,得到不正确的结果。如果DECIMAL的存储结果超过最大范围,建议将整数和小数分开存储

  1. 【强制】如果存储的字符串长度几乎相等,使用CHAR定长字符串类型
  2. 【强制】VARCHAR是可变长字符串,不预留分配存储空间,长度不要超过5000.如果存储长度大于此值,定义字段为TEXT,独立出来一张表,用主键来对应,避免影响其他字段索引效率

路漫漫其修远兮,吾将上下而求索