当前位置: 首页 > news >正文

【深入浅出MySQL】之数据类型介绍

【深入浅出MySQL】之数据类型介绍

  • MySQL中常见的数据类型一览
  • 为什么需要如此多的数据类型
  • 数值类型
    • BIT(M)类型
    • INT类型
    • TINYINT类型
    • BIGINT类型
    • 浮点数类型
      • float类型
      • DECIMAL(M,D)类型
      • 区别总结
  • 字符串类型
    • CHAR类型
    • VARCHAR(M)类型
  • 日期和时间类型
  • enum和set类型

前言:MySQL是一种广泛使用的关系型数据库管理系统,它提供了多种数据类型供开发者去选择,以此来满足不同的场景。

MySQL中常见的数据类型一览

类别数据类型描述存储范围/长度常见用途
数值类型TINYINT非常小的整数-128 到 127(有符号);0 到 255(无符号)存储小的整数,如状态码(0/1)、年龄等
BITM位类型,M指定位数,默认值1M的范围(1~64)适用于需要存储二进制信息的情况,例如标志位、布尔值数组等。通过使用 BIT 类型,可以更有效地存储和操作位级别的数据。
SMALLINT小整数-32,768 到 32,767(有符号);0 到 65,535(无符号)存储中等范围的整数,如计数器、小范围的ID
MEDIUMINT中等大小的整数-8,388,608 到 8,388,607(有符号);0 到 16,777,215(无符号)存储中等范围的整数,较少使用
INT / INTEGER标准整数-2,147,483,648 到 2,147,483,647(有符号);0 到 4,294,967,295(无符号)存储常用整数,如用户ID、订单号等
BIGINT大整数-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807(有符号)存储大范围整数,如大型系统的ID、计数器
FLOAT单精度浮点数约 ±3.4E+38(7位有效数字)存储近似数值,如价格、科学计算数据
DOUBLE双精度浮点数约 ±1.79E+308(15位有效数字)存储更高精度的近似数值,如金融数据、科学计算
DECIMAL(M,D)定点数(精确小数)M 是总位数,D 是小数位数,例如 DECIMAL(10,2) 存储 8位整数+2位小数存储精确小数,如货币金额(避免浮点误差)
字符串类型CHAR(M)固定长度字符串0 到 255 个字符存储固定长度的字符串,如状态码、性别(‘M’/‘F’)
VARCHAR(M)可变长度字符串0 到 65,535 个字符(取决于字符集和存储引擎)存储可变长度的字符串,如用户名、地址
TINYTEXT短文本字符串最大 255 个字符存储短文本,如备注、小段描述
TEXT标准文本字符串最大 65,535 个字符存储较长的文本,如文章内容、评论
MEDIUMTEXT中等长度文本字符串最大 16,777,215 个字符存储中等长度的文本,如长篇文章
LONGTEXT超长文本字符串最大 4,294,967,295 个字符存储超长文本,如日志文件、JSON 数据
ENUM('value1', 'value2', ...)枚举类型,只能从预定义值中选择一个值最多 65,535 个不同值存储固定选项,如状态(‘active’/‘inactive’)、性别(‘male’/‘female’)
SET('value1', 'value2', ...)集合类型,可以选择多个预定义值(以逗号分隔)最多 64 个不同值存储多选选项,如兴趣(‘reading,swimming’)
日期和时间类型DATE日期1000-01-01 到 9999-12-31存储日期,如生日、注册日期
TIME时间-838:59:59 到 838:59:59存储时间,如一天中的时间点、持续时间
DATETIME日期和时间组合1000-01-01 00:00:00 到 9999-12-31 23:59:59存储完整的日期和时间,如创建时间、更新时间
TIMESTAMP时间戳(从 1970-01-01 00:00:00 UTC 开始)1970-01-01 00:00:00 到 2038-01-19 03:14:07(UTC)存储时间戳,常用于记录数据更新时间(自动更新)
YEAR年份1901 到 2155(4位格式);70 到 69(2位格式,1970-2069)存储年份,如出生年份、发布年份
其他类型BINARY(M)固定长度的二进制字符串0 到 255 个字节存储固定长度的二进制数据,如校验码
VARBINARY(M)可变长度的二进制字符串0 到 65,535 个字节存储可变长度的二进制数据,如小型文件
BLOB二进制大对象最大 65,535 个字节存储二进制数据,如图片、文件
MEDIUMBLOB中等长度的二进制大对象最大 16,777,215 个字节存储中等大小的二进制数据,如较大的文件
LONGBLOB超长二进制大对象最大 4,294,967,295 个字节存储超大二进制数据,如视频文件
JSONJSON 格式数据(MySQL 5.7+ 支持)最大 1GB(受限于存储引擎)存储 JSON 数据,如配置信息、动态字段

为什么需要如此多的数据类型

似乎单一数据类型如字符类型可以存储所有的数据,但事实上,我们需要如此多的数据类型的原因有以下几种:

  • 数据的准确性与合法性需求:有时候我们描述某一个列时,如果这个列只能是整数,而不能出现小数点(如id),此时如果只有字符类型就满足不了需求,而整数类型和浮点数类型的存在就可以有效防止非法的数据进入数据库中。
  • 性能上
    • 空间上:如果只有单一的INT类型的整数,有时候某些列的大小永远不会超过某一个整数值,这个时候使用INT就很浪费空间,所以使用 TINYINT 来存储 0 到 255 范围内的整数比使用 VARCHAR 更节省空间。
    • 时间上:对于数值运算,直接使用数值类型而不是字符串类型进行计算会更加高效。这是因为数值类型可以直接参与算术运算,而字符串则需要先转换成数值形式才能进行相应的操作,这增加了额外的处理开销。
  • 功能上
    • 日期时间处理:专门的日期时间类型(如 DATE, TIME, DATETIME)提供了丰富的函数支持,方便进行日期计算、格式化输出等操作。如果用字符串表示日期时间,则需要手动编写代码来进行这些操作,不仅复杂而且容易出错。
  • 查询优化:
    • 索引利用:某些数据类型允许创建特定类型的索引(如全文索引适用于 TEXT 类型),从而提高查询能力。如果所有数据都以字符串形式存储,则可能无法充分利用这些高级索引功能。

数值类型

BIT(M)类型

BIT是位类型,其中M是位数,如果你想精确控制该列的位数,可以使用这个类型。

  1. 创建一个表tt1,表中有一个num列,它的类型是BIT(1)

    image-20250323160326121

  2. 表创建成功了:

    image-20250323160352415

  3. 向表中插入数据:

    image-20250323160647744

    • 超过1就插入失败,因为bit位的位数位1,只能表示01
    • 但是发现一个很奇怪的现象,就算查表,1没有显示出来。
  4. 这是因为bit类型是默认是按照ASCII码,1对应的符号是不可显示的特殊符号。

    image-20250323161104285

  5. 测试一下bit类型位数的边界情况:

    create table tt3(num bit(65));
    create table tt4(num bit(0));
    

    image-20250323161255461

[!tip]

如果我们有一些列,只需要0或者1就可以使用bit(1),这样非常节省空间。

INT类型

INT类型的范围:-2,147,483,648 到 2,147,483,647(有符号);0 到 4,294,967,295(无符号)

这和我们C语言中的是相符的。

但C语言中溢出后会截断,数据库是否会这样呢?

  1. 首先我们创建表tt4

    create table tt4(num int);
    
  2. 查看表tt4:

    image-20250323162142786

    • int后面的数字的含义:这是表示的默认宽度,通常配合ZEROFILL属性使用,这个后面我们再谈,和C语言中的printf的格式控制符很像。
  3. 插入一个数字,我们测试int的边界,插入21474836472,147,483,648,-2,147,483,648 -2,147,483,649

    image-20250323215634411

TINYINT类型

TINYINT也是整数类型,但是它只能表示-128 到 127(有符号),0 到 255(无符号)当你的列需要一个整数类型来表示,但是不会超过255时就可以使用这个类型。

  1. 创建表tt5

    create table tt5(num tinyint);
    
  2. 越界测试:

    insert into tt5 values(128);
    

    image-20250323220704189

BIGINT类型

大整数类型,它能表示-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807(有符号),适合做大型系统的id列的类型、计数器等。

  1. 创建表tt6

    create table tt6(num bigint);
    
  2. 数据类型边界测试:

    insert into tt6 values(-9223372036854775808);
    

    image-20250323221222211

浮点数类型

float类型

语法(syntax)

float[(m, d)] [unsigned] : M指定显示长度,d指定小数位数,占用空间4
  1. 创建表tt7,它有一个num列是float(5,2)类型,长度为5,小数位数为2,它可以表示999.99 ~ -999.99的值:

    create table tt7(float(5,2));
    
  2. 插入一些值观察现象:

    mysql> insert into tt7 values(999.99999999);
    ERROR 1264 (22003): Out of range value for column 'num' at row 1
    mysql> insert into tt7 values(999.99);
    Query OK, 1 row affected (0.00 sec)mysql> insert into tt7 values(999.93);
    Query OK, 1 row affected (0.00 sec)mysql> insert into tt7 values(-999.999);
    ERROR 1264 (22003): Out of range value for column 'num' at row 1
    mysql> insert into tt7 values(-999.99);
    Query OK, 1 row affected (0.00 sec)mysql> insert into tt7 values(-9999);
    ERROR 1264 (22003): Out of range value for column 'num' at row 1
    mysql> insert into tt7 values(-99);Query OK, 1 row affected (0.00 sec)
    mysql> select * from tt7;
    +---------+
    | num     |
    +---------+
    |  999.99 |
    |  999.93 |
    | -999.99 |
    |  -99.00 |
    +---------+
    • 可以看到依旧会发生越界的情况。
  3. 如果我们插入的值长度超过M,但是范围又在此时[M,d]所限定的范围内,就会发生四舍五入的情况:

    image-20250323222356706

DECIMAL(M,D)类型

M 是总位数,D 是小数位数,例如 DECIMAL(10,2) 存储 8位整数+2位小数

听上去好像和float没什么区别呀,我们来建个表插入数据看看:

  1. 创建表tt8,它有一列num,数据类型为decimal(5,2),存储3位整数+2位小数:

    create table tt8(num decimal(5,2));
    
  2. 插入一些值,然后观察现象:

    insert into tt8 values(999.976)
    ...
    

    image-20250323223540971

  • 它似乎也和float一样也会进行越界判断,也会四舍五入,那它们有什么区别呢?

区别总结

我们从实际的现象来观察并思考为什么会这样。

  1. 创建表tt9

    create table tt9(num1 float(10,1),num2 decimal(10,1));
    
  2. 插入下面的值:

    insert into tt9(999999998,999999998);
    
  3. 表中最终的结果:

    mysql> select * from tt9;
    +--------------+-------------+
    | num1         | num2        |
    +--------------+-------------+
    | 1000000000.0 | 999999998.0 |
    +--------------+-------------+
    
    • 居然!,num1被近似成了1000000000.0 ,而且总长度是11位,我们不是规定了总长度吗?这个num2是正常显示的。
  4. 我们手动插入一下一行让num11000000000.0,看能否成功:

    mysql> insert into tt9 values(1000000000.0,999999998);
    ERROR 1264 (22003): Out of range value for column 'num1' at row 1
    
    • 很明显失败了,MySQL报错了。

总结

  • FLOAT 是近似类型:它不保证精确存储和显示,可能会对大数值进行近似处理。
  • DECIMAL 是精确类型:它严格按照定义的范围和精度存储和显示数据。
  • 显示宽度不受严格限制:FLOAT(M,D) 的定义主要用于限制存储范围(也就是限制用户的),但实际显示的宽可能会因为近似超出定义的范围。

所以如果我们的列对数据的精确性要求很高,且是浮点数,就需要使用DECIMAL类型。

字符串类型

CHAR类型

语法:char(L):固定长度字符串,不管用户输入的字符串的长度为多少,MySQL都会拿出L的长度给该列,L的最大值是255

[!caution]

MySQL里面的一个长度就对应一个字符,不管你是中文、英文字符、还是特殊字符都只占一个长度单位,也就是说MySQL对于字符长度有自己的标准。在 MySQL 中,字符长度单位指的是字符的数量,而不是字节数。但是,实际占用的存储空间取决于字符集。

下面我们创建表,插入一些值来验证一下:

  1. 创建表tt10

    create table tt10(s char(5));
    
  2. 插入一些字符:

    insert into tt10 values('你好世界呀');
    insert into tt10 values('abcde');
    insert into tt10 values('abcdef');
    

    image-20250323230740596

  • 我们都知道实际上中文字符的存储字节和英文字符的存储字节一般是不同的,要看具体的存储编码,所以在 MySQL 中,字符长度单位指的是字符的数量,而不是字节数。

[!caution]

如果你插入的字符的长度比L小,MySQL会自动填充空格。

VARCHAR(M)类型

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

  1. 创建表tt11

    create table tt11(s varchar(10));
    
  2. 插入一些字符串:

    insert into tt11 values("111");
    insert into tt11 values("1111111111");
    

    image-20250324172213459

[!caution]

变长并不是这个类型存储的字符的长度可以超过用户指定的长度L,而是当用户实际存储的字符长度没有L时,MySQL不会使用空格填充,这样节省了空间。

如何选择charvarchar类型

  1. 如果指定列的字符串长度是固定的,就使用char类型。
  2. 当存储大量可变长度的字符串时,可以使用varchar来节省存储空间。
  3. CHAR 因为是定长的,存储和检索效率更高,尤其是在频繁访问和更新的场景中。
  4. VARCHAR 因为需要额外的长度信息,存储和检索效率略低,但在现代数据库系统中,这种差异通常不明显。

日期和时间类型

MySQL中日期类型(如 DATEDATETIMETIMESTAMP 等)是非常重要的数据类型。它们的存在是为了更高效地存储、查询和操作与时间相关的数据。

日期类型可以表示广泛的日期范围,远超过普通字符串或数字能表达的范围。例如:

  • DATE 类型支持从 ‘1000-01-01’ 到 ‘9999-12-31’ 的日期。
  • DATETIMETIMESTAMP 支持精确到秒甚至微秒的时间点。

下面我们创建一个表,使用一下日期类型:

  1. 创建表tt12

    create table tt12(d1 date,d2 datetime,t timestamp);
    
  2. 插入一些值:

    insert into tt12 values('1922-01-22','1922-01-22 00:00:00',FROM_UNIXTIME(1));
    
    • TIMESTAMP 不支持直接插入原始的 Unix 时间戳(如 1742947200),需要通过 FROM_UNIXTIME() 函数进行转换。插入当前时间:可以使用 NOW()CURRENT_TIMESTAMP 来插入当前时间。

    • DATETIME存储日期和时间。

    • DATE只存储日期。

      image-20250324174151354

enum和set类型

ENUM(枚举)类型是一种字符串对象,其值范围必须来自一个预定义的列表。这些值是按定义顺序排列的,并且只能选择列表中的值之一。

SET 类型是一种字符串对象,它可以包含零个或多个由逗号分隔的值,这些值来自于一个预定义的列表。与 ENUM 不同的是,SET 允许一个字段包含多个值。

使用介绍:

  1. 创建表tt13

    create table tt13(identity enum('学生','老师','工人'), set permissions('write','read','exec'));
    
  2. 插入一些值:

    mysql> insert into tt13 values('学生','write,res');
    ERROR 1265 (01000): Data truncated for column 'permissions' at row 1
    mysql> insert into tt13 values('学生','write,read');
    Query OK, 1 row affected (0.00 sec)mysql> insert into tt13 values('学生','write');
    Query OK, 1 row affected (0.00 sec)mysql> insert into tt13 values('学生,老师','write');
    ERROR 1265 (01000): Data truncated for column 'identity' at row 1
    mysql> insert into tt13 values('学生1','write');
    ERROR 1265 (01000): Data truncated for column 'identity' at row 1

    image-20250324174923450

应用场景

  • 使用 ENUM
    • 当字段的值是单一选项时。
    • 需要确保数据一致性且选项数量较少。
    • 场景示例:性别、状态、分类等。
  • 使用 SET
    • 当字段的值是多个选项的组合时。
    • 需要灵活的多选功能且选项数量较少。
    • 场景示例:权限、兴趣爱好、标签等。

相关文章:

  • ES6入门---第三单元 模块一:类、继承
  • 分享一个Android中文汉字手写输入法并带有形近字联想功能
  • DeepSeek Copilot idea插件推荐
  • Allegro23.1新功能之如何设置高压爬电间距规则操作指导
  • Mamba+Attention+CNN 预测模型:破局长程依赖的计算机视觉新范式
  • ActiveMQ 与其他 MQ 的对比分析:Kafka/RocketMQ 的选型参考(二)
  • 【JLINK调试器】适配【大华HC32F4A0芯片】的完整解决方案
  • 数据结构--树状数组
  • opencv的contours
  • ABC404G 题解
  • 数据结构(4) 堆
  • Terraform 中的 external 数据块是什么?如何使用?
  • 软考-软件设计师中级备考 12、软件工程
  • Java 中使用 Callable 创建线程的方法
  • 【办公类-99-04】20250504闵豆统计表excle转PDF,合并PDF、添加中文字体页眉+边框下划线
  • postgresql数据库基本操作
  • JVM happens-before 原则有哪些?
  • 数字信号处理学习笔记--Chapter 1 离散时间信号与系统
  • AndroidLogger常用命令和搜索功能介绍
  • ESP32S3 多固件烧录方法、合并多个固件为单一固件方法
  • 儿童文学作家周晴病逝,享年57岁
  • 这 3 种食物,不要放进微波炉!第 1 个就大意了
  • 社区来电催生?多地回应:系为居民提供卫生健康服务
  • 原油价格战一触即发?沙特不想再忍,领衔多个产油国加速增产
  • 五一假期前三日多景区客流刷新纪录,演艺、古镇、山水都很火
  • 纽约大都会博物馆展“萨金特与巴黎”:从艺术生到明星画家