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

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

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

MySQL中常见的数据类型一览

类别 数据类型 描述 存储范围/长度 常见用途
数值类型 TINYINT 非常小的整数 -128 到 127(有符号);0 到 255(无符号) 存储小的整数,如状态码(0/1)、年龄等
BITM 位类型,M指定位数,默认值1 M的范围(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 个字节 存储超大二进制数据,如视频文件
JSON JSON 格式数据(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)

  2. 表创建成功了:

  3. 向表中插入数据:

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

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

    sql 复制代码
    create table tt3(num bit(65));
    create table tt4(num bit(0));

!tip

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

INT类型

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

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

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

  1. 首先我们创建表tt4

    sql 复制代码
    create table tt4(num int);
  2. 查看表tt4:

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

TINYINT类型

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

  1. 创建表tt5

    sql 复制代码
    create table tt5(num tinyint);
  2. 越界测试:

    sql 复制代码
    insert into tt5 values(128);

BIGINT类型

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

  1. 创建表tt6

    sql 复制代码
    create table tt6(num bigint);
  2. 数据类型边界测试:

    sql 复制代码
    insert into tt6 values(-9223372036854775808);

浮点数类型

float类型

语法(syntax)

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

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

    sql 复制代码
    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]所限定的范围内,就会发生四舍五入的情况:

DECIMAL(M,D)类型

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

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

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

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

    sql 复制代码
    insert into tt8 values(999.976)
    ...
  • 它似乎也和float一样也会进行越界判断,也会四舍五入,那它们有什么区别呢?

区别总结

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

  1. 创建表tt9

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

    sql 复制代码
    insert into tt9(999999998,999999998);
  3. 表中最终的结果:

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

    sql 复制代码
    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

    sql 复制代码
    create table tt10(s char(5));
  2. 插入一些字符:

    sql 复制代码
    insert into tt10 values('你好世界呀');
    insert into tt10 values('abcde');
    insert into tt10 values('abcdef');
  • 我们都知道实际上中文字符的存储字节和英文字符的存储字节一般是不同的,要看具体的存储编码,所以在 MySQL 中,字符长度单位指的是字符的数量,而不是字节数。

!caution

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

VARCHAR(M)类型

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

  1. 创建表tt11

    sql 复制代码
    create table tt11(s varchar(10));
  2. 插入一些字符串:

    sql 复制代码
    insert into tt11 values("111");
    insert into tt11 values("1111111111");

!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

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

    sql 复制代码
    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只存储日期。

enum和set类型

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

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

使用介绍:

  1. 创建表tt13

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

    sql 复制代码
    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

应用场景

  • 使用 ENUM
    • 当字段的值是单一选项时。
    • 需要确保数据一致性且选项数量较少。
    • 场景示例:性别、状态、分类等。
  • 使用 SET
    • 当字段的值是多个选项的组合时。
    • 需要灵活的多选功能且选项数量较少。
    • 场景示例:权限、兴趣爱好、标签等。
相关推荐
志存高远661 小时前
kotlin 扩展函数
android·开发语言·kotlin
coding随想1 小时前
深入浅出数据库规范化的三大范式
数据库·oracle
爱笑的眼睛112 小时前
uniapp 云开发全集 云数据库
javascript·数据库·oracle·uni-app
柯南二号3 小时前
Android 实现一个隐私弹窗
android
尤物程序猿4 小时前
【2025最新】为什么用ElasticSearch?和传统数据库MySQL与什么区别?
数据库·mysql·elasticsearch
别来无恙1494 小时前
MySQL JOIN详解:掌握数据关联的核心技能
数据库·mysql
小小不董5 小时前
Oracle OCP认证考试考点详解083系列06
linux·数据库·oracle·dba
Dy大叔5 小时前
ThinkPHP 5 根据账户类型的不同统计数据中使用CASE WHEN THEN SQL语句实例
mysql·php
一 乐5 小时前
宿舍报修|宿舍报修小程序|基于Java微信小程序的宿舍报修系统的设计与实现(源码+数据库+文档)
java·数据库·微信小程序·小程序·论文·毕设·宿舍报修小程序