MySQL数据类型全面解析:从数值精度到字符串优化的最佳实践
目录
- 1. 数据类型分类
- 2. 数值类型
- 2.1 tinyint类型
- 2.2 bit类型
- 2.3 小数类型
- 2.3.1 float类型
- 2.3.2 decimal类型
- 3. 字符串类型
- 3.1 char类型
- 3.2 varchar类型
- 3.3 char和varchar比较
- 4. 日期和时间类型
- 5. enum和set类型
- 5.1 enum类型
- 5.2 set类型
1. 数据类型分类
MySQL中的数据类型主要分为数值类型、字符串类型、日期和时间类型、枚举和集合类型等。
2. 数值类型
2.1 tinyint类型
基本语法:
tinyint[(m)] [unsigned]
数值越界测试:
-- 创建表(默认有符号)
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-- 查询结果
mysql> select * from tt1;
+------+
| num |
+------+
| 1 |
+------+
无符号案例:
-- 创建无符号tinyint表
mysql> create table tt2(num tinyint unsigned);-- 插入负数报错
mysql> insert into tt2 values(-1);
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)-- 查询结果
mysql> select * from tt2;
+------+
| num |
+------+
| 255 |
+------+
重要说明:
- 整型默认是有符号的
- 可以通过
UNSIGNED关键字指定为无符号 - 建议尽量不使用unsigned,对于存放不下的数据,直接升级为更大的类型(如bigint)
2.2 bit类型
基本语法:
bit[(M)]
M表示每个值的位数,范围从1到64,默认为1。
示例:
-- 创建表
mysql> create table tt4 (id int, a bit(8));
Query OK, 0 rows affected (0.01 sec)-- 插入数据
mysql> insert into tt4 values(10, 10);
Query OK, 1 row affected (0.01 sec)-- 查询显示(按照ASCII码显示)
mysql> select * from tt4;
+------+------+
| id | a |
+------+------+
| 10 | |
+------+------+-- 插入ASCII码为65的数据(对应字符'A')
mysql> insert into tt4 values(65, 65);
mysql> select * from tt4;
+------+------+
| id | a |
+------+------+
| 10 | |
| 65 | A |
+------+------+
bit使用的注意事项:
- bit字段显示时按照ASCII码对应的值显示
- 对于只存放0或1的值,可以定义bit(1)来节省空间
- 插入越界值会报错
-- 创建存储性别的表
mysql> create table tt5(gender bit(1));-- 正常插入
mysql> insert into tt5 values(0);
mysql> insert into tt5 values(1);-- 越界插入
mysql> insert into tt5 values(2);
ERROR 1406 (22001): Data too long for column 'gender' at row 1
2.3 小数类型
2.3.1 float类型
语法:
float[(m, d)] [unsigned]
- m:指定显示长度
- d:指定小数位数
- 占用空间:4个字节
示例:
-- 创建表
mysql> create table tt6(id int, salary float(4,2));
Query OK, 0 rows affected (0.01 sec)-- 插入数据(自动四舍五入)
mysql> insert into tt6 values(100, -99.99);
mysql> insert into tt6 values(101, -99.991);
Query OK, 1 row affected (0.00 sec)-- 查询结果
mysql> select * from tt6;
+------+--------+
| id | salary |
+------+--------+
| 100 | -99.99 |
| 101 | -99.99 |
+------+--------+
无符号float:
-- 创建无符号float表
mysql> create table tt7(id int, salary float(4,2) unsigned);-- 插入负数报错
mysql> insert into tt7 values(100, -0.1);
ERROR 1264 (22003): Out of range value for column 'salary' at row 1-- 正常插入
mysql> insert into tt7 values(100, 0);
mysql> insert into tt7 values(100, 99.99);
2.3.2 decimal类型
语法:
decimal(m, d) [unsigned]
- m:指定长度
- d:表示小数点的位数
精度比较:
-- 创建表比较float和decimal精度
mysql> create table tt8 (id int, salary float(10,8), salary2 decimal(10,8));-- 插入数据
mysql> insert into tt8 values(100, 23.12345612, 23.12345612);
Query OK, 1 row affected (0.00 sec)-- 查询比较
mysql> select * from tt8;
+------+-------------+-------------+
| id | salary | salary2 |
+------+-------------+-------------+
| 100 | 23.12345695 | 23.12345612 |
+------+-------------+-------------+
重要说明:
- float表示的精度大约是7位
- decimal整数最大位数m为65,支持小数最大位数d是30
- 如果希望小数的精度高,推荐使用decimal
3. 字符串类型
3.1 char类型
语法:
char(L)
固定长度字符串,L是可以存储的长度(单位为字符),最大长度值为255。
示例:
-- 创建表
mysql> create table tt9(id int, name char(2));
Query OK, 0 rows affected (0.00 sec)-- 插入英文字符
mysql> insert into tt9 values(100, 'ab');
Query OK, 1 row affected (0.00 sec)-- 插入中文字符
mysql> insert into tt9 values(101, '中国');
Query OK, 1 row affected (0.00 sec)-- 查询结果
mysql> select * from tt9;
+------+--------+
| id | name |
+------+--------+
| 100 | ab |
| 101 | 中国 |
+------+--------+-- 超过最大长度报错
mysql> create table tt10(id int, name char(256));
ERROR 1074 (42000): Column length too big for column 'name' (max = 255)
3.2 varchar类型
语法:
varchar(L)
可变长度字符串,L表示字符长度,最大长度65535个字节。
示例:
-- 创建表
mysql> create table tt10(id int, name varchar(6));-- 插入数据
mysql> insert into tt10 values(100, 'hello');
mysql> insert into tt10 values(100, '我爱你,中国');-- 查询结果
mysql> select * from tt10;
+------+--------------------+
| id | name |
+------+--------------------+
| 100 | hello |
| 100 | 我爱你,中国 |
+------+--------------------+
varchar长度说明:
- 实际可用字节数:65532(因为有1-3个字节用于记录数据大小)
- 编码影响:
- utf8编码:最大长度 = 65532/3 = 21844
- gbk编码:最大长度 = 65532/2 = 32766
-- 验证utf8编码下的最大长度
mysql> create table tt11(name varchar(21845)) charset=utf8;
ERROR 1118 (42000): Row size too large.mysql> create table tt11(name varchar(21844)) charset=utf8;
Query OK, 0 rows affected (0.01 sec)
3.3 char和varchar比较
选择建议:
| 类型 | 适用场景 | 特点 |
|---|---|---|
| char | 数据长度固定(身份证、手机号、MD5) | 磁盘空间浪费,但效率高 |
| varchar | 数据长度变化(名字、地址) | 磁盘空间节省,但效率低 |
设计原则:
- 定长数据使用char:直接开辟对应空间
- 变长数据使用varchar:用多少开辟多少
4. 日期和时间类型
常用类型:
date:日期 ‘yyyy-mm-dd’,占用3字节datetime:时间日期 ‘yyyy-mm-dd HH:ii:ss’,范围1000-9999,占用8字节timestamp:时间戳,从1970年开始,格式同datetime,占用4字节
示例:
-- 创建表
mysql> create table birthday (t1 date, t2 datetime, t3 timestamp);
Query OK, 0 rows affected (0.01 sec)-- 插入数据
mysql> insert into birthday(t1,t2) values('1997-7-1','2008-8-8 12:1:1');
Query OK, 1 row affected (0.00 sec)-- 查询结果(timestamp自动填充当前时间)
mysql> select * from birthday;
+------------+---------------------+---------------------+
| t1 | t2 | t3 |
+------------+---------------------+---------------------+
| 1997-07-01 | 2008-08-08 12:01:01 | 2023-11-12 18:28:55 |
+------------+---------------------+---------------------+-- 更新数据(timestamp自动更新)
mysql> update birthday set t1='2000-1-1';
Query OK, 1 row affected (0.00 sec)mysql> select * from birthday;
+------------+---------------------+---------------------+
| t1 | t2 | t3 |
+------------+---------------------+---------------------+
| 2000-01-01 | 2008-08-08 12:01:01 | 2023-11-12 18:32:09 |
+------------+---------------------+---------------------+
5. enum和set类型
5.1 enum类型
语法:
enum('选项1','选项2','选项3',...)
- "单选"类型
- 实际存储数字(1,2,3,…),最多65535个选项
5.2 set类型
语法:
set('选项值1','选项值2','选项值3',...)
- "多选"类型
- 实际存储数字(1,2,4,8,16,32,…),最多64个选项
示例:
-- 创建调查表
mysql> create table votes(-> username varchar(30),-> hobby set('登山','游泳','篮球','武术'),-> gender enum('男','女')
);
Query OK, 0 rows affected (0.02 sec)-- 插入数据
insert into votes values('雷锋', '登山,武术', '男');
insert into votes values('Juse', '登山,武术', 2); -- 使用数字标识
insert into votes values('LiLei', '登山', '男');
insert into votes values('LiLei', '篮球', '男');
insert into votes values('HanMeiMei', '游泳', '女');-- 查询所有数据
mysql> select * from votes;
+-----------+---------------+--------+
| username | hobby | gender |
+-----------+---------------+--------+
| 雷锋 | 登山,武术 | 男 |
| Juse | 登山,武术 | 女 |
| LiLei | 登山 | 男 |
| LiLei | 篮球 | 男 |
| HanMeiMei | 游泳 | 女 |
+-----------+---------------+--------+
集合查询:
-- 错误查询方式(只能查询完全匹配)
mysql> select * from votes where hobby='登山';
+----------+--------+--------+
| username | hobby | gender |
+----------+--------+--------+
| LiLei | 登山 | 男 |
+----------+--------+--------+-- 正确查询方式:使用find_in_set函数
mysql> select * from votes where find_in_set('登山', hobby);
+----------+---------------+--------+
| username | hobby | gender |
+----------+---------------+--------+
| 雷锋 | 登山,武术 | 男 |
| Juse | 登山,武术 | 女 |
| LiLei | 登山 | 男 |
+----------+---------------+--------+
find_in_set函数:
-- 语法:find_in_set(sub, str_list)
mysql> select find_in_set('a', 'a,b,c');
+---------------------------+
| find_in_set('a', 'a,b,c') |
+---------------------------+
| 1 |
+---------------------------+mysql> select find_in_set('d', 'a,b,c');
+---------------------------+
| find_in_set('d', 'a,b,c') |
+---------------------------+
| 0 |
+---------------------------+
