MySQL数据类型详解:数值、字符串、日期时间与JSON分类指南

阿麦
阿麦
发布时间:2026-09-22| 3人浏览过
原创

MySQL字段的数据类型决定了数据库能够保存什么内容、如何比较和计算这些内容,以及需要占用多少存储空间。实际建表时,最常用的类型可以归纳为四组:保存数量和金额的数值类型、保存文本和二进制内容的字符串类型、保存日期时间的时间类型,以及保存结构化动态数据的JSON类型。选择时不需要追求“越大越保险”,而应先看数据的含义,再确定范围、精度、长度以及是否需要参与计算和索引。

一、先理解MySQL数据类型是怎样分类的

一个字段应该使用什么类型,首先取决于它代表的是什么。例如用户年龄属于整数,商品价格需要精确的小数,用户名属于字符串,订单创建时间属于日期时间,而一组结构不固定的扩展属性则可能适合JSON。

从日常业务开发的角度,可以把常见MySQL数据类型理解为下面几类。

MySQL数据类型详解:数值、字符串、日期时间与JSON分类指南
图1:MySQL常用字段类型可以先按“数据代表什么”进行分类,再决定具体类型。

这种分类方式比死记所有类型名称更实用。比如看到“金额”,应该先想到精确数值,再在DECIMAL等类型中选择,而不是因为金额中存在小数就直接使用FLOAT。

二、数值类型:整数、定点数和浮点数分别什么时候用

MySQL中的数值类型主要解决三个问题:整数、要求精确的小数,以及允许近似表示的小数。这三类数据看起来都属于“数字”,实际用途差别很大。

1. 整数类型

常用整数类型包括TINYINT、SMALLINT、MEDIUMINT、INT和BIGINT。它们的主要区别是能够表示的数值范围以及占用的存储空间。

类型 典型用途 选择思路
TINYINT 状态、小范围数量 数值范围明确且很小时使用
SMALLINT 中小范围整数 比TINYINT范围更大,但不需要INT时使用
MEDIUMINT 介于SMALLINT和INT之间的数据 对空间较敏感且范围明确时考虑
INT 常规编号、计数、数量 通用整数场景中最常见
BIGINT 可能非常大的ID或累计值 明确可能超过INT范围时使用

例如商品库存不需要小数,可以定义为整数:

stock INT NOT NULL DEFAULT 0

如果字段从业务含义上不允许出现负数,可以根据实际需求考虑无符号整数:

stock INT UNSIGNED NOT NULL DEFAULT 0

不过不要只因为“现在不会出现负数”就机械地给所有字段添加UNSIGNED。数据库设计还需要考虑未来是否存在差额、修正值或其他需要负数的场景。

2. 金额优先考虑DECIMAL

价格、余额、结算金额等数据通常要求十进制意义上的精确结果,这时更适合使用DECIMAL。

例如:

price DECIMAL(10,2) NOT NULL

这里的DECIMAL(10,2)表示总共最多保存10位十进制数字,其中2位位于小数点后。因此它适合类似下面的金额:

19.90
1280.00
99999999.99

如果是账户余额、订单金额或财务统计,不应仅仅因为数据有小数就默认选择FLOAT或DOUBLE。浮点数使用的是近似表示方式,某些十进制小数无法被二进制浮点格式精确表达。

3. FLOAT和DOUBLE适合允许近似值的计算

FLOAT和DOUBLE适合科学计算、测量值、统计数据等允许存在浮点近似误差的场景。通常DOUBLE能够提供比FLOAT更高的精度,但也需要更多空间。

例如一个用于记录传感器测量值的字段,可以使用:

temperature DOUBLE

选择数值类型时,可以按照下面的顺序判断,而不是从类型名称反推用途。

MySQL数据类型详解:数值、字符串、日期时间与JSON分类指南
图2:数值类型的实用选择步骤,重点是先判断整数、精确小数还是近似小数。

三、字符串类型:CHAR、VARCHAR、TEXT怎么选

字符串类型用于保存名称、标题、邮箱、URL、文章正文等文本信息。常见选择并不是简单的“短字符串用VARCHAR,长字符串用TEXT”,还要看长度是否固定、是否需要频繁索引以及字段的实际语义。

1. CHAR适合长度相对固定的数据

CHAR(n)适合长度固定或基本固定的字符串。例如某些固定格式代码可以考虑:

country_code CHAR(2)

如果一个字段大部分数据长度变化很大,则通常没有必要为了固定长度而使用CHAR。

2. VARCHAR是业务表中最常见的文本类型之一

用户名、文章标题、邮箱、文件路径等长度会变化但通常存在合理上限的内容,往往适合使用VARCHAR。

username VARCHAR(50) NOT NULL,
email VARCHAR(255) NOT NULL,
title VARCHAR(200) NOT NULL

这里的长度应该根据业务约束确定,而不是看到VARCHAR就统一定义成某个很大的值。

例如用户名规定最多50个字符,使用VARCHAR(50)能够直接表达这一业务限制。相比之下,把所有字符串都定义成非常大的VARCHAR,会使表结构失去对数据含义的表达能力,同时还可能影响索引设计。

3. TEXT适合较长正文

对于文章内容、备注、详情描述等长度可能明显超过普通标题和名称的数据,可以考虑TEXT系列类型。

content TEXT

MySQL还提供不同容量级别的TEXT类型,例如TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT。实际选择时应根据可能出现的数据长度确定,而不是默认使用容量最大的类型。

4. BLOB保存的是二进制数据

TEXT主要保存字符数据,而BLOB系列用于保存二进制数据。如果内容本质上不是文本,例如某些二进制文件内容,就属于另一类问题。

不过在Web系统中,大型图片、视频和附件通常更常见的做法是保存到文件系统或对象存储中,数据库只记录路径、URL、对象键和元数据。是否直接把二进制内容放入数据库,需要结合备份、访问方式、文件规模和系统架构判断。

5. ENUM和SET不要仅仅因为“写起来方便”就使用

MySQL还提供ENUM和SET。ENUM允许字段从预先定义的一组值中选择一个,而SET允许选择其中多个。

例如:

status ENUM('draft', 'published', 'disabled')

这种方式能够直接在字段定义中约束取值,但如果业务状态频繁变化,修改枚举定义会增加数据库结构变更成本。因此应根据业务稳定程度决定是否使用。

四、日期时间类型:不要把时间全部保存成VARCHAR

日期和时间如果需要排序、筛选、计算或使用MySQL的日期函数,应优先使用专门的时间类型,而不是把2026-09-22 16:30:00这样的内容保存到VARCHAR中。

常见类型主要有DATE、TIME、DATETIME、TIMESTAMP和YEAR。

1. DATE只保存日期

如果业务只需要“哪一天”,而不关心具体时分秒,就可以使用:

birthday DATE

典型值类似:

1995-08-18

2. TIME用于时间或时间间隔

只需要表示时间部分时可以考虑TIME。例如某些营业时长、时间值或持续时间场景可以使用TIME,但具体使用前需要确认业务语义是否与MySQL TIME类型相匹配。

3. DATETIME适合保存明确的日期和时间

文章发布时间、预约时间等需要完整年月日和时分秒的信息,可以使用DATETIME:

published_at DATETIME

4. TIMESTAMP与时区处理有关

TIMESTAMP同样可以表示日期和时间,但它与MySQL会话时区之间存在转换关系。这一点是它和DATETIME在实际使用中的重要区别之一。

简单来说,如果业务需要记录一个统一的时间点,并希望数据库在不同时区的会话中进行相应转换,可以研究TIMESTAMP是否符合系统设计;如果希望保存的日期时间值本身保持不变,则DATETIME往往更容易理解。

注意:时间类型的选择不仅是“DATETIME和TIMESTAMP哪个更省空间”的问题。跨时区系统还需要统一应用层、数据库连接和服务器的时区策略,否则同一个时间点可能在不同环节产生理解偏差。
MySQL数据类型详解:数值、字符串、日期时间与JSON分类指南
图3:时间类型需要区分日期、日期时间和时区语义;JSON则更适合作为动态结构的补充,而不是替代所有普通字段。

五、JSON类型:适合动态属性,但不是“万能字段”

MySQL提供原生JSON类型,可以保存JSON对象、数组以及其他合法JSON值。与直接把JSON文本保存到普通VARCHAR或TEXT中相比,JSON字段能够让数据库识别其结构,并使用相应的JSON函数进行读取和处理。

例如商品可能存在一些不固定的扩展属性:

{
  "color": "black",
  "memory": "16GB",
  "ports": ["USB-C", "HDMI"]
}

可以建立一个JSON字段:

attributes JSON

插入示例数据:

INSERT INTO products
    (name, price, attributes)
VALUES
    (
        '示例笔记本',
        5999.00,
        JSON_OBJECT(
            'color', 'black',
            'memory', '16GB',
            'ports', JSON_ARRAY('USB-C', 'HDMI')
        )
    );

读取JSON内部属性时,可以使用MySQL提供的JSON操作方式。例如获取color:

SELECT attributes->>'$.color' AS color
FROM products;

示例结果:

black

什么时候适合JSON

JSON比较适合下面这类数据:

  • 不同记录可能拥有不同扩展属性;
  • 属性数量和名称不是完全固定;
  • 这些属性属于主记录的辅助信息;
  • 需要保留对象或数组这样的层级结构。

什么时候不应该为了省事全部使用JSON

如果字段是稳定、核心并且经常用于查询,例如商品名称、用户ID、价格、订单状态,就更适合建立明确的普通字段。

例如下面这种设计通常不够合理:

CREATE TABLE products (
    id BIGINT PRIMARY KEY,
    data JSON
);

然后把商品名称、价格、库存、状态和创建时间全部放入data中。这样虽然字段看起来少了,但核心数据的约束、索引、查询以及表结构可读性都会变得更加复杂。

更自然的设计是:

CREATE TABLE products (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    name VARCHAR(200) NOT NULL,
    price DECIMAL(10,2) NOT NULL,
    stock INT UNSIGNED NOT NULL DEFAULT 0,
    status TINYINT NOT NULL DEFAULT 1,
    attributes JSON,
    created_at DATETIME NOT NULL,
    PRIMARY KEY (id)
);

这里把稳定字段拆成普通列,把结构不固定的扩展属性交给JSON处理,两者各自承担适合自己的职责。

六、BOOLEAN实际上应该怎样理解

MySQL允许在字段定义中写BOOLEAN或BOOL,但在MySQL的数据类型体系中,它们是TINYINT(1)的同义表示。

例如:

is_active BOOLEAN NOT NULL DEFAULT TRUE

在应用程序里,可以把0理解为false,把非0值理解为true。对于确实只有“开/关”“是/否”两个状态的字段,这种写法具有较好的可读性。

如果字段实际存在多个状态,例如“待审核、已发布、已下架”,就不要把它设计成布尔类型,而应使用能够明确表达多个状态的字段。

七、不要把“编号”一律理解成数值

判断字段类型时,一个很容易出现的错误是看到内容由数字组成,就认为必须使用INT。

例如:

  • 订单流水号;
  • 手机号;
  • 邮政编码;
  • 身份证件编号;
  • 带前导零的业务编码。

这些内容虽然可能主要由数字字符组成,但通常并不用于数学运算。“编号”和“数值”不是同一个概念。

例如一个代码值:

001258

如果保存为整数,它会变成:

1258

原有的前导零已经失去。因此,如果业务关注的是字符串形式本身,通常应该根据实际长度使用CHAR或VARCHAR,而不是仅根据字符看起来像数字就选择整数。

八、一个完整建表示例:把不同类型放到真实结构中理解

假设现在要建立一个简单的商品表,需要保存商品ID、名称、价格、库存、是否上架、上架日期、创建时间以及扩展属性。

可以写成:

CREATE TABLE products (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    name VARCHAR(200) NOT NULL,
    price DECIMAL(10,2) NOT NULL,
    stock INT UNSIGNED NOT NULL DEFAULT 0,
    is_enabled BOOLEAN NOT NULL DEFAULT TRUE,
    online_date DATE NULL,
    attributes JSON NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

逐个看这些字段为什么这样设计:

  • id是递增整数,并考虑较大的数据规模,因此示例使用BIGINT;
  • name长度变化明显,但存在合理上限,因此使用VARCHAR;
  • price属于需要精确表示的金额,因此使用DECIMAL;
  • stock只保存非负整数,因此示例使用无符号INT;
  • is_enabled只有开启和关闭两个含义,可以使用BOOLEAN;
  • online_date只关心哪一天,因此使用DATE;
  • attributes用于存放不固定的扩展属性,因此使用JSON;
  • created_at需要记录完整创建日期和时间,因此使用DATETIME。

这里真正重要的不是复制这个表结构,而是观察每个字段类型都能对应一个明确的数据含义。

九、设计字段时可以按照这几个步骤判断

如果面对一个新字段不知道应该使用哪种类型,可以按下面的顺序处理。

  1. 先确定字段保存的是什么。是数量、价格、名称、正文、日期、时间点还是动态属性。
  2. 判断是否需要数学运算。数字字符不等于数值,手机号和编码通常属于字符串。
  3. 如果是小数,判断是否需要精确。金额优先考虑DECIMAL,允许近似误差的数据再考虑FLOAT或DOUBLE。
  4. 如果是字符串,确定合理长度。固定长度可以考虑CHAR,长度变化且有上限通常使用VARCHAR,较长正文考虑TEXT。
  5. 如果是时间,确定需要日期、时间还是完整时间点。不要为了方便全部保存为VARCHAR。
  6. 只有结构确实动态时再考虑JSON。经常查询和约束的核心字段通常仍应定义为独立列。

十、常见的类型选择错误

所有整数都使用BIGINT

BIGINT能保存很大的值,但“范围更大”并不代表所有字段都应该使用它。状态、小范围数量和普通计数应根据真实范围选择类型。

所有字符串都定义成很大的VARCHAR

字段长度本身也是数据库结构的一部分。用户名、标题、URL和验证码的含义明显不同,应该尽量通过合理的字段长度表达约束。

金额使用FLOAT

如果业务要求十进制金额计算准确,应该优先使用DECIMAL,而不是依赖近似浮点数。

时间保存为VARCHAR

这样会失去专门日期时间类型带来的比较、排序、日期函数和语义表达能力,同时还需要额外处理格式一致性。

为了避免加字段,把所有属性塞进JSON

JSON适合解决动态结构问题,而不是替代关系型数据库中的所有普通列。稳定、核心、需要查询和约束的数据仍然适合独立字段。

MySQL数据类型详解:数值、字符串、日期时间与JSON分类指南
图4:MySQL常见数据类型总结。先按业务数据的真实含义确定大类,再决定范围、长度和精度。

十一、最终应该怎样选择MySQL数据类型

MySQL数据类型并不需要靠死记所有名称来掌握。实际开发时,可以把问题简化成几个判断:数据是不是数值、是否要求精确、字符串长度是否固定、是否属于日期时间,以及结构是否经常变化。

可以记住下面这组核心对应关系:

  • 普通整数:根据范围选择TINYINT、INT、BIGINT等;
  • 金额和其他精确小数:优先考虑DECIMAL;
  • 允许近似的小数计算:根据精度要求考虑FLOAT或DOUBLE;
  • 长度固定的字符串:可以考虑CHAR;
  • 长度变化并有合理上限的文本:通常使用VARCHAR;
  • 较长正文:根据容量考虑TEXT系列;
  • 日期或日期时间:使用DATE、DATETIME、TIMESTAMP等专门类型;
  • 结构不固定的扩展属性:可以考虑JSON,但核心字段仍应优先设计成普通列。

字段类型选得合理,带来的不只是存储空间上的区别。它还能让数据库结构更清楚,使约束、排序、计算、索引和查询都更符合数据本身的含义。因此,设计表结构时最值得关注的问题不是“哪个类型最万能”,而是“这个字段在业务中究竟代表什么,以及数据库以后准备怎样使用它”。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。