Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL数值、字符串到时间详解

MySQL全数据类型从数值、字符串到时间详解(手把手选型避坑)

作者:小叶-duck

在MySQL数据库设计中,数据类型的选择直接影响存储效率、查询性能和数据准确性,这篇文章主要介绍了MySQL全数据类型从数值、字符串到时间的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

在 MySQL 库表设计工作里,字段数据类型的选取,会直接左右数据库的存储空间占用、索引查询效率与数据存储可靠性。合理选定数据类型,可以有效压缩磁盘占用、杜绝数值溢出、规避浮点精度丢失等常见故障;倘若类型选用不当,极易埋下长期隐患,例如使用整型存储超长手机号而造成数据截断。本文会逐一拆解 MySQL 全部常用数据类型,搭配落地测试案例梳理选型思路,带你摆脱随意定义字段的习惯,熟练掌握规范、高效的数据类型使用方法。

一、MySQL 数据类型体系整体梳理与分类介绍

MySQL 的数据类型丰富,按功能可分为五大类,覆盖数值、字符串、日期、特殊类型等场景:

分类核心类型适用场景
数值类型BIT、TINYINT、INT、BIGINT、FLOAT、DECIMAL存储数字(年龄、金额、计数等)
字符串类型CHAR、VARCHAR、TEXT、BLOB存储文本(姓名、地址、大文本、二进制数据)
日期时间类型DATE、DATETIME、TIMESTAMP存储时间(生日、创建时间、时间戳)
特殊字符串ENUM(枚举)、SET(集合)固定选项(性别、爱好、状态等)
二进制类型BLOB存储图片、文件等二进制数据

二、数值类型:依照数值区间与精度要求合理选定类型

数值类型是最常用的类型,核心关注范围和精度,避免数据溢出或精度丢失。

2.1 整数类型:BIT、TINYINT、INT、BIGINT 特性解析

整数类型按占用字节和范围分为 5 类,支持 UNSIGNED(无符号)修饰(默认有符号):

类型占用字节有符号范围无符号范围适用场景
BIT(M)1-81-64 位(默认 1 位)同有符号存储 0/1(性别)、位掩码
TINYINT1-128 ~ 1270 ~ 255年龄、状态值(0-255)
SMALLINT2-32768 ~ 327670 ~ 65535小范围计数(如订单编号)
INT4-2147483648 ~ 21474836470 ~ 4294967295普通计数(如用户ID)
BIGINT8-9e18 ~ 9e180 ~ 1.8e19大数值(如手机号、学生ID)

关键实战要点

  1. 谨慎使用 UNSIGNED 无符号修饰,工程中尽量不使用:无符号仅能拓宽正数上限,存在明显缺陷:插入负数会直接触发报错、且与有符号类型计算时容易出现逻辑问题;同时无符号整型溢出无平滑容错,线上故障概率更高。 扩容优先选用更大的基础整型,例如需要 0~300 范围,直接用 INT,而非 TINYINT UNSIGNED,兼容性与稳定性更优。

  2. BIT 类型局限性强,日常业务尽量少用:BIT 用于存放二进制位,查询结果会按照 ASCII 字符展示,可读性极差:BIT (8) 存入 10 会显示换行符、存入 65 会展示字符 A,调试排查十分麻烦。 它仅适合存储少量 0/1 标记、位掩码,不要用来存放常规数字,布尔状态优先选用 TINYINT (1) 替代 BIT。

2.1.1 TINYINT 类型测试

TINYINT 占用 1 字节,有符号范围 - 128~127,无符号范围 0~255:

-- 1. 创建有符号TINYINT表
CREATE TABLE test_tinyint1(age TINYINT);

-- 2. 插入合法值
INSERT INTO test_tinyint1 VALUES(127); -- 成功(最大值)
INSERT INTO test_tinyint1 VALUES(-128); -- 成功(最小值)

-- 3. 插入越界值(报错)
INSERT INTO test_tinyint1 VALUES(128); 
-- 报错:Out of range value for column 'age' at row 1

-- 4. 创建无符号TINYINT表
CREATE TABLE test_tinyint2(age TINYINT UNSIGNED);

-- 5. 插入无符号合法值
INSERT INTO test_tinyint2 VALUES(255); -- 成功(无符号最大值)

-- 6. 插入负数(无符号越界报错)
INSERT INTO test_tinyint2 VALUES(-1); 
-- 报错:Out of range value for column 'age' at row 1

2.1.2 BIT 类型测试

BIT 存储位数据,默认 1 位(仅支持 0/1),位数 M 需 ≤ 64,对于老版本的 MySQL 查询时会按 ASCII  码显示(易踩坑),而对于较新版本的 MySQL 会显示成16进制,大家可以自己去试试:

-- 1. 创建BIT(1)字段的表
CREATE TABLE test_bit(gender BIT(1));

-- 2. 插入合法值(0/1)
INSERT INTO test_bit VALUES(0); -- 成功
INSERT INTO test_bit VALUES(1); -- 成功

-- 3. 插入越界值(报错)
INSERT INTO test_bit VALUES(2); 
-- 报错:Data truncation: Data too long for column 'gender' at row 1

-- 4. 查询BIT字段(关键:直接查询显示ASCII字符,需转成数字)
SELECT gender, bin(gender+0) FROM test_bit;

运行结果:

+--------+---------------+
| gender | bin(gender+0) |
+--------+---------------+
|       | 0             | -- 0的ASCII显示为空白,转数字后是0
|       | 1             | -- 1的ASCII显示为,转数字后是1
+--------+---------------+

2.1.3 INT/BIGINT 对比测试

-- 1. INT存储手机号(越界测试)
CREATE TABLE test_int(phone INT);
INSERT INTO test_int VALUES(13800138000); 
-- 报错:Out of range value for column 'phone' at row 1(INT最大值2147483647 < 13800138000)

-- 2. BIGINT存储手机号(成功)
CREATE TABLE test_bigint(phone BIGINT);
INSERT INTO test_bigint VALUES(13800138000); -- 成功
SELECT * FROM test_bigint;
+-------------+
| phone       |
+-------------+
| 13800138000 |
+-------------+

2.2 小数类型:FLOAT、DOUBLE、DECIMAL 辨析

小数类型用于存储带小数点的数值,核心区别在于精度:

类型占用字节精度特性适用场景
FLOAT4单精度,约 7 位有效数字非精确计算(如身高、体重)
DOUBLE8双精度,约 15 位有效数字较高精度计算(如温度)
DECIMAL可变高精度(自定义整数 + 小数位)精确计算(如金额、税率)

2.2.1 FLOAT 类型测试

语法:

float[(m, d)] [unsigned] : -- M指定显示长度,d指定小数位数,占用空间4个字节

有符号 float 测试:

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);
Query OK, 1 row affected (0.00 sec)

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 |
+------+--------+
2 rows in set (0.00 sec)

无符号 float 测试:

mysql> create table tt7(id int, salary float(4,2) unsigned);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into tt7 values(100, -0.1);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+-------------------------------------------------+
| Level   | Code | Message                                         |
+---------+------+-------------------------------------------------+
| Warning | 1264 | Out of range value for column 'salary' at row 1 |
+---------+------+-------------------------------------------------+
1 row in set (0.00 sec)

mysql> insert into tt7 values(100, -0);
Query OK, 1 row affected (0.00 sec)

mysql> insert into tt7 values(100, 99.99);
Query OK, 1 row affected (0.00 sec)

2.2.2 DECIMAL 类型测试

2.2.3 FLOAT 与 DECIMAL 精度误差对照实验

-- 1. 创建小数测试表
CREATE TABLE test_decimal(
  salary_float FLOAT(10,8),
  salary_decimal DECIMAL(10,8)
);

-- 2. 插入相同数值
INSERT INTO test_decimal VALUES(23.12345612, 23.12345612);

-- 3. 查询结果(精度差异)
SELECT * FROM test_decimal;

运行结果:

+---------------+----------------+
| salary_float  | salary_decimal |
+---------------+----------------+
| 23.12345695   | 23.12345612    |
+---------------+----------------+

三、字符串类型:CHAR 与 VARCHAR 场景抉择

字符串类型是最容易用错的类型,核心是区分 CHAR(固定长度)和 VARCHAR(可变长度),以及 TEXT(大文本)的适用场景。

3.1 核心字符串类型对比

类型长度限制存储特性适用场景
CHAR(L)L ≤ 255(字符)固定长度,不足自动补空格长度固定内容(身份证、手机号)
VARCHAR(L)L ≤ 65535(字节)可变长度,额外占用1~3字节记录长度长度不固定文本(姓名、地址)
TEXT最大 65535 字节大文本类型,不支持默认值、普通索引长文本(文章内容、大段备注)
BLOB最大 65535 字节二进制原始存储图片、文件等二进制数据

3.2 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 | 中国   |
+------+--------+

      说明: char(2) 表示可以存放两个字符,可以是字母或汉字,但是不能超过2个, 最多只能 255。

mysql> create table tt10(id int ,name char(256));
ERROR 1074 (42000): Column length too big for column 'name' (max = 255); use 
BLOB or TEXT instead

3.3 VARCHAR 类型测试

语法:

varchar(L): -- 可变长度字符串,L表示字符长度,最大长度65535个字节

实战案例:

mysql> create table tt10(id int ,name varchar(6)); --表示这里可以存放6个字符
mysql> insert into tt10 values(100, 'hello'); 
mysql> insert into tt10 values(100, '我爱你,中国');
mysql> select * from tt10;
+------+--------------------+
| id   | name               |
+------+--------------------+
|  100 | hello              |      
|  100 | 我爱你,中国        |
+------+--------------------+ 

3.4 CHAR、VARCHAR 存储机制深度实测

-- 1. 创建CHAR/VARCHAR对比表(UTF8编码,1字符=3字节)
CREATE TABLE test_char_varchar(
  c_char CHAR(4),
  c_varchar VARCHAR(4)
) CHARSET=utf8;

-- 2. 插入不同长度数据
INSERT INTO test_char_varchar VALUES('abcd', 'abcd'); -- 4字符
INSERT INTO test_char_varchar VALUES('A', 'A'); -- 1字符
INSERT INTO test_char_varchar VALUES('中国', '中国'); -- 2字符

-- 3. 查询数据(查看实际存储)
SELECT 
  c_char, LENGTH(c_char), -- CHAR长度:固定12字节(4×3)
  c_varchar, LENGTH(c_varchar) -- VARCHAR长度:实际字符×3 + 1字节
FROM test_char_varchar;

运行结果:

+--------+---------------+------------+------------------+
| c_char | LENGTH(c_char)| c_varchar  | LENGTH(c_varchar)|
+--------+---------------+------------+------------------+
| abcd   |            12 | abcd       |               13 |
| A      |            12 | A          |                4 |
| 中国   |             6 | 中国        |                7 |
+--------+---------------+------------+------------------+

关键结论:

如何选择定长或变长字符串?

  • 如果数据确定长度都一样,就使用定长(char),比如:身份证,手机号,md5
  • 如果数据长度有变化,就使用变长(varchar), 比如:名字,地址,但是你要保证最长的能存的进去。
  • 定长的磁盘空间比较浪费,但是效率高。
  • 变长的磁盘空间比较节省,但是效率低。
  • 定长的意义是,直接开辟好对应的空间
  • 变长的意义是,在不超过自定义范围的情况下,用多少,开辟多少。

四、日期时间类型:DATE / DATETIME / TIMESTAMP 选型方案

日期时间类型用于存储时间相关数据,核心是区分三者的存储范围、时区特性和自动更新机制:

类型占用字节时间范围时区特性自动更新适用场景
DATE31000-01-01~9999-12-31无无生日、日期记录
DATETIME81000-01-01~9999-12-31无无固定时间(如订单创建时间)
TIMESTAMP41970-01-01~2038-01-19受时区影响支持自动更新时间戳(如最后修改时间)

4.1 TIMESTAMP 自动更新特性实操演示

-- 1. 创建日期测试表
CREATE TABLE test_datetime(
  t1 DATE,
  t2 DATETIME,
  t3 TIMESTAMP
);

-- 2. 仅插入DATE/DATETIME,TIMESTAMP自动填充当前时间
INSERT INTO test_datetime(t1,t2) VALUES('1997-07-01','2008-08-08 12:01:01');

-- 3. 查询初始结果
SELECT * FROM test_datetime;

运行结果 1:

+------------+---------------------+---------------------+
| t1         | t2                  | t3                  |
+------------+---------------------+---------------------+
| 1997-07-01 | 2008-08-08 12:01:01 | 2024-05-20 15:30:22 | -- t3自动填充当前时间
+------------+---------------------+---------------------+
-- 4. 更新数据,TIMESTAMP自动刷新
UPDATE test_datetime SET t1='2000-01-01';

-- 5. 查询更新结果
SELECT * FROM test_datetime;

运行结果 2:

+------------+---------------------+---------------------+
| t1         | t2                  | t3                  |
+------------+---------------------+---------------------+
| 2000-01-01 | 2008-08-08 12:01:01 | 2024-05-20 15:35:48 | -- t3自动更新为修改时间
+------------+---------------------+---------------------+

五、 特殊字符串类型:ENUM 单选、SET 多选场景落地

ENUM(枚举)和 SET(集合)适用于固定选项的场景,避免手动校验输入合法性。

5.1 ENUM 枚举单选类型用法实测

-- 1. 创建枚举表
CREATE TABLE test_enum(
  username VARCHAR(30),
  gender ENUM('男','女')
);

-- 2. 插入合法值
INSERT INTO test_enum VALUES('雷锋','男'); -- 成功
INSERT INTO test_enum VALUES('小红',2); -- 成功(2对应第二个选项'女')

-- 3. 插入非法值(报错)
INSERT INTO test_enum VALUES('Tom','未知'); 
-- 报错:Data truncated for column 'gender' at row 1

-- 4. 查询枚举值
SELECT username, gender, gender+0 FROM test_enum; -- gender+0查看枚举对应的数字

运行结果:

+----------+--------+-----------+
| username | gender | gender+0  |
+----------+--------+-----------+
| 雷锋     | 男     |         1 |
| 小红     | 女     |         2 |
+----------+--------+-----------+

5.2 SET 集合多选类型用法实测

-- 1. 创建集合表
CREATE TABLE test_set(
  username VARCHAR(30),
  hobby SET('登山','游泳','篮球','武术')
);

-- 2. 插入多选值
INSERT INTO test_set VALUES('雷锋','登山,武术'); -- 成功
INSERT INTO test_set VALUES('小红','游泳'); -- 成功(单选)

-- 3. 插入非法值(自动忽略)
INSERT INTO test_set VALUES('Tom','登山,游戏'); -- '游戏'不是选项,仅插入'登山'

查询指定爱好的语句:

mysql> select * from votes where hobby='登山';
+----------+-----------+
| username | hobby     |
+----------+-----------+
| Tom      | 登山      |
+----------+-----------+

      问题:不能查询出所有,爱好为登山的人。

      集合查询使用 find_ in_ set 函数:
       find_in_set(sub, str_list):如果 sub 在 str_list 中,则返回下标;如果不在,返回0; 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 |
+---------------------------+

查询所有包含但不仅限于爱好登山的人:

-- 4. 查询包含某选项的记录(find_in_set函数)
SELECT * FROM test_set WHERE FIND_IN_SET('登山', hobby);

运行结果:

+----------+-----------+
| username | hobby     |
+----------+-----------+
| 雷锋     | 登山,武术  |
| Tom      | 登山      |
+----------+-----------+

六、数据类型选型经验汇总与常见踩坑规避

总结: MySQL 数据类型的选择核心是 “匹配场景 + 平衡性能与空间”

  • BIT/TINYINT 有严格范围限制,插入越界值会直接报错,查询 BIT 需转数字;
  • FLOAT 存在精度丢失,金额等精确场景必须用 DECIMAL;
  • CHAR 适合固定长度字符串(如手机号),VARCHAR 适合可变长度字符串(如姓名);
  • TIMESTAMP 支持自动更新,但有 2038 年限制,普通场景优先用 DATETIME;
  • ENUM/SET 简化固定选项存储,SET 查询需用 find_in_set 函数。

结束语

本篇系统梳理了 MySQL 常用数据类型的分类、底层存储特性与实战测试,从整数、浮点高精度数值,到定长 / 变长字符串、日期时间、枚举集合等类型逐一拆解,对比了不同类型的取值范围、空间开销、精度缺陷与使用边界。

日常建库建表时,很多性能隐患、数据错乱、存储空间冗余问题,根源往往都是数据类型随意选取:一味用大类型造成空间浪费、选用浮点类型存储金额引发精度丢失、滥用 TIMESTAMP 遭遇 2038 时限陷阱、VARCHAR 长度乱定义浪费索引效率。

MySQL 数据类型是数据库优化的基石,熟练掌握各类类型的优劣与适用场景,后续索引设计、SQL 调优、分库分表等进阶优化才能落地生根。后续我们可以结合索引、事务等内容,继续深挖 MySQL 底层原理,不断夯实数据库工程实践能力。

到此这篇关于MySQL全数据类型从数值、字符串到时间的文章就介绍到这了,更多相关MySQL数值、字符串到时间详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文