
◆ 博主名称: 小此方-CSDN博客 大家好,欢迎来到小此方的博客。
⭐️Linux系列个人专栏: 【主题曲】Mysql
⭐️此方的GitHub: github_此方
⭐️ Re系列专栏:我们思考 (Rethink) · 我们重建 (Rebuild) · 我们记录 (Record)
文章目录
- 概要&序論
- 一、MySQL数据类型概览与分类
-
- [1.1 数据类型分类总览](#1.1 数据类型分类总览)
- [1.2 数值类型的详细范围](#1.2 数值类型的详细范围)
- 二、数值类型详解
-
- [2.1 tinyint类型](#2.1 tinyint类型)
- [2.2 bit类型](#2.2 bit类型)
- [2.3 小数类型](#2.3 小数类型)
-
- [2.3.1 float](#2.3.1 float)
- [2.3.2 decimal](#2.3.2 decimal)
- 三、字符串类型
-
- [3.1 char](#3.1 char)
- [3.2 varchar](#3.2 varchar)
- [3.3 char和varchar比较](#3.3 char和varchar比较)
- 四、日期和时间类型
- 五、enum和set
-
- [5.1 案例演示](#5.1 案例演示)
- [5.2 集合查询](#5.2 集合查询)
概要&序論
Hello大家好,我是此方,在几个月前更新过Mysql后来因为Linux网络专栏而停更了一段时间。从本文开始我们将继续更新内容。本文延续上一篇文章。讲解Mysql中常见的数据类型。
一、MySQL数据类型概览与分类
在MySQL中,选择合适的数据类型对于数据库的性能和存储空间至关重要。不同的数据类型有着不同的存储范围和应用场景。
1.1 数据类型分类总览
MySQL的数据类型主要分为四大类:数值类型、文本与二进制类型、时间日期类型以及String类型。具体的分类与说明如下表所示。
| 分类 | 数据类型 | 说明 |
|---|---|---|
| 数值类型 | BIT(M) | 位类型,M指定位数,默认1,范围1-64 |
| 数值类型 | TINYINT UNSIGNED | 带符号范围-128~127,无符号范围0~255,默认有符号 |
| 数值类型 | BOOL | 使用0和1表示真和假 |
| 数值类型 | SMALLINT UNSIGNED | 带符号是-2^15次方到2^15-1,无符号是2^16-1 |
| 数值类型 | INT UNSIGNED | 带符号是-2^31次方到2^31-1,无符号是2^32-1 |
| 数值类型 | BIGINT UNSIGNED | 带符号是-2^63次方到2^63-1,无符号是2^64-1 |
| 数值类型 | FLOAT(M,D) UNSIGNED | M指定显示长度,D指定小数位数,占用4字节 |
| 数值类型 | DOUBLE(M,D) UNSIGNED | 比float精度更大的小数,占用8字节 |
| 数值类型 | DECIMAL(M,D) UNSIGNED | 定点数,M指定长度,D表示小数点的位数 |
| 文本、二进制类型 | CHAR(size) | 固定长度字符串,最大255 |
| 文本、二进制类型 | VARCHAR(size) | 可变长度字符串,最大长度65535 |
| 文本、二进制类型 | BLOB | 二进制数据 |
| 文本、二进制类型 | TEXT | 大文本,不支持全文索引,不支持默认值 |
| 时间日期 | DATE/DATETIME/TIMESTAMP | 日期、日期时间、时间戳格式 |
| String类型 | ENUM类型 | 枚举字符串对象,值来自创建时指定的允许值 |
| String类型 | SET类型 | 集合字符串对象,可包含多个值,以逗号隔开 |
1.2 数值类型的详细范围
对于整数类型,带符号(有符号)和无符号(UNSIGNED)的存储范围有显著差异,具体字节数和极值如下表。
| 类型 | 字节 | 最小值(带符号) | 最大值(带符号) | 最小值(无符号) | 最大值(无符号) |
|---|---|---|---|---|---|
| TINYINT | 1 | -128 | 127 | 0 | 255 |
| SMALLINT | 2 | -32768 | 32767 | 0 | 65535 |
| MEDIUMINT | 3 | -8388608 | 8388607 | 0 | 16777215 |
| INT | 4 | -2147483648 | 2147483647 | 0 | 4294967295 |
| BIGINT | 8 | -9223372036854775808 | 9223372036854775807 | 0 | 18446744073709551615 |
二、数值类型详解
在了解了大致分类后,我们详细来看看常用的数值类型。对于整数类型,在MySQL中,整型可以指定是有符号的和无符号的,默认是有符号的,可以通过UNSIGNED来说明某个字段是无符号的。
2.1 tinyint类型
我们以tinyint为例进行数值越界测试,创建一个带有tinyint字段的表并尝试插入数据。
sql
mysql> create table tt1(num tinyint);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into tt1 values(1);
Query OK, 1 row affected (0.00 sec)
mysql> insert into tt1 values(128); -- 越界插入,报错
ERROR 1264 (22003): Out of range value for column 'num' at row 1
如果是无符号的情况,范围则变成了0到255。
sql
mysql> create table tt2(num tinyint unsigned);
mysql> insert into tt2 values(-1); -- 无符号,范围是:0 - 255
ERROR 1264 (22003): Out of range value for column 'num' at row 1
mysql> insert into tt2 values(255);
Query OK, 1 row affected (0.02 sec)
这里有一个建议,尽量不使用unsigned。对于int类型可能存放不下的数据,int unsigned同样可能存放不下,与其如此,还不如设计时,直接将int类型提升为bigint类型。



2.2 bit类型
bit(M)是位字段类型,M表示每个值的位数,范围从1到64。如果M被忽略,默认为1。但需要注意的是,bit字段在显示时,是按照ASCII码对应的值显示。
sql
mysql> create table tt4 (id int, a bit(8));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into tt4 values(10, 10);
mysql> select * from tt4; # 发现很怪异的现象,a的数据10没有出现,因为10对应ASCII码的换行符,通常不可见
+------+------+
| id | a |
+------+------+
| 10 | |
+------+------+
如果我们插入65,就会显示为大写字母A。如果我们有这样的值,只存放0或1,这时可以定义bit(1)。这样可以节省空间。比如定义 gender bit(1),插入2则会报错越界。


2.3 小数类型
小数类型主要分为float和decimal,它们在使用和精度上有显著区别。
2.3.1 float
语法为 float[(m, d)] [unsigned],其中M指定显示长度,d指定小数位数,占用空间4个字节。小数 float(4,2) 表示的范围是 -99.99 ~ 99.99,MySQL在保存值时会进行四舍五入。
sql
mysql> create table tt6(id int, salary float(4,2));
mysql> insert into tt6 values(100, -99.99);
mysql> insert into tt6 values(101, -99.991); # 多的这一点被拿掉了,四舍五入成了-99.99
如果定义的是 float(4,2) unsigned,这时,因为把它指定为无符号的数,范围是 0 ~ 99.99。如果插入负数如-0.1,会产生警告并截断为0。
2.3.2 decimal
语法为 decimal(m, d) [unsigned],定点数m指定长度,d表示小数点的位数。decimal(5,2) 表示的范围是 -999.99 ~ 999.99。它和float很像,但最大的区别在于精度。
sql
mysql> create table tt8 (id int, salary float(10,8), salary2 decimal(10,8));
mysql> insert into tt8 values(100,23.12345612,23.12345612);
mysql> select * from tt8;
+------+-------------+-------------+
| id | salary | salary2 |
+------+-------------+-------------+
| 100 | 23.12345695 | 23.12345612 |
+------+-------------+-------------+
通过对比发现,decimal的精度更准确,因此如果我们希望某个数据表示高精度,选择decimal。float表示的精度大约是7位。decimal整数最大位数m为65,支持小数最大位数d是30。如果d被省略,默认为0;如果m被省略,默认是10。


三、字符串类型
字符串类型中最常用的就是char和varchar,我们需要理解它们底层的存储差异。
3.1 char
语法为 char(L),是固定长度字符串,L是可以存储的长度,单位为字符,最大长度值可以为255。char(2)表示可以存放两个字符,可以是字母或汉字,但是不能超过2个,最多只能是255,如果定义 char(256) 则直接报错。
3.2 varchar
语法为 varchar(L),是可变长度字符串,L表示字符长度,最大长度65535个字节。关于varchar(len)中len到底能设置多大,和表的编码密切相关。
varchar长度可以指定为0到65535之间的值,但是有1-3个字节用于记录数据大小,所以说有效字节数是65532。当我们的表的编码是utf8时,varchar(n)的参数n最大值是 65532/3=21844(因为utf8中一个字符占用3个字节);如果编码是gbk,varchar(n)的参数n最大是 65532/2=32766(因为gbk中一个字符占用2字节)。
3.3 char和varchar比较
如何选择定长或变长字符串?主要依据以下几点。
- 如果数据确定长度都一样,就使用定长char,比如身份证、手机号、md5。
- 如果数据长度有变化,就使用变长varchar,比如名字、地址,但是你要保证最长的能存的进去。
- 定长的磁盘空间比较浪费,但是效率高,它的意义是直接开辟好对应的空间。
- 变长的磁盘空间比较节省,但是效率低,它的意义是在不超过自定义范围的情况下,用多少开辟多少。


四、日期和时间类型
常用的日期类型有三个:date表示日期,格式为 yyyy-mm-dd,占用三字节;datetime表示时间日期,格式为 yyyy-mm-dd HH:ii:ss,表示范围从1000到9999,占用八字节;timestamp表示时间戳,从1970年开始的 yyyy-mm-dd HH:ii:ss 格式和datetime完全一致,占用四字节。
timestamp有一个特殊属性,在添加或更新数据时,时间戳会自动补上或更新成当前时间。
sql
mysql> create table birthday (t1 date, t2 datetime, t3 timestamp);
mysql> insert into birthday(t1,t2) values('1997-7-1','2008-8-8 12:1:1');
-- 此时t3时间戳会自动补上当前时间
mysql> update birthday set t1='2000-1-1';
-- 更新数据,t3时间戳会自动更新成当前时间

五、enum和set
enum是枚举类型,属于"单选"类型,语法为 enum(选项1,选项2,选项3...)。该设定只是提供了若干个选项的值,最终一个单元格中,实际只存储了其中一个值;出于效率考虑,这些值实际存储的是"数字",依次对应 1, 2, 3... 最多65535个。
set是集合类型,属于"多选"类型,语法为 set(选项值1,选项值2,选项值3...)。一个单元格中可以设计存储其中任意多个值;同样出于效率考虑,这些值实际存储的也是"数字",依次对应 1, 2, 4, 8, 16, 32... 最多64个。不建议在添加枚举值、集合值的时候采用数字的方式,因为不利于阅读。
5.1 案例演示
我们创建一个调查表votes,需要调查人的喜好(可以多选),以及性别(单选)。
sql
mysql> create table votes(
-> username varchar(30),
-> hobby set('登山','游泳','篮球','武术'),
-> gender enum('男','女')
-> );
Query OK, 0 rows affected (0.02 sec)
插入数据时,可以直接用字符串,也可以使用数字下标。
sql
insert into votes values('雷锋','登山,武术','男');
insert into votes values('Juse','登山,武术',2);
select * from votes where gender=2;
5.2 集合查询
假设有数据 Juse 爱好 登山,武术,LiLei 爱好 登山,HanMeiMei 爱好 游泳。我们想查找所有喜欢登山的人,如果使用 select * from votes where hobby='登山';,是不能查询出所有爱好为登山的人的,只能查出行完全匹配 '登山' 的记录。
集合查询需要使用 find_in_set 函数。find_in_set(sub,str_list) 的含义是:如果sub在str_list中,则返回下标;如果不在,返回0;str_list是用逗号分隔的字符串。正确的查询语句如下。
sql
mysql> select * from votes where find_in_set('登山', hobby);

好的本文内容到此结束,我是此方,我们下期再见。