MySQL: MySQL数据类型详解与选择指南

最后更新:2026-08-26

数据类型决定了数据怎么存、占多大空间、能做什么运算——选错类型后患无穷。

本课系统讲解 MySQL 所有数据类型及选择策略。

100%
graph TB
    A[MySQL 数据类型] --> B[整数类型]
    A --> C[浮点/定点类型]
    A --> D[字符串类型]
    A --> E[日期时间类型]
    A --> F[JSON 类型]
    B --> B1[TINYINT]
    B --> B2[SMALLINT]
    B --> B3[INT]
    B --> B4[BIGINT]
    C --> C1[FLOAT]
    C --> C2[DOUBLE]
    C --> C3[DECIMAL]
    D --> D1[CHAR]
    D --> D2[VARCHAR]
    D --> D3[TEXT]
    D --> D4[ENUM]
    E --> E1[DATE]
    E --> E2[DATETIME]
    E --> E3[TIMESTAMP]

1. 你将学到


2. 一个精度问题的真实故事

(1) 痛点:金额算错了

一个电商系统用 FLOAT 存储商品价格:

SQL
-- 演示浮点精度丢失
SELECT 0.1 + 0.2;  -- 结果: 0.300000004(近似值,不精确)

-- 存入表后更明显
CREATE TABLE float_demo (price FLOAT);
INSERT INTO float_demo VALUES (199.99);
SELECT price FROM float_demo;  -- 结果: 199.99(显示正确但内部存储有微小误差)
SELECT price + 0.01 FROM float_demo;  -- 累积误差可能在运算中暴露

1,000 笔交易后,累积的精度误差让财务对账差了几块钱。

(2) DECIMAL 的解法

SQL
-- DECIMAL 精确存储,无误差
CREATE TABLE decimal_demo (price DECIMAL(10,2));
INSERT INTO decimal_demo VALUES (199.99);
SELECT price + 0.01 FROM decimal_demo;  -- 结果: 200.00(精确)

结果:price = 200.00,精确无误差。

类型 精度 适用场景
FLOAT 近似(6-7 位) 科学计算、不要求精确
DOUBLE 近似(15-16 位) 科学计算
DECIMAL 精确 金额、财务数据

3. 整数类型

类型 字节 有符号范围 无符号范围
TINYINT 1 -128 ~ 127 0 ~ 255
SMALLINT 2 -32,768 ~ 32,767 0 ~ 65,535
MEDIUMINT 3 -8,388,608 ~ 8,388,607 0 ~ 16,777,215
INT 4 -2,147,483,648 ~ 2,147,483,647 0 ~ 4,294,967,295
BIGINT 8 -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 0 ~ 18,446,744,073,709,551,615

▶ 示例:整数类型

SQL
CREATE TABLE user_stats (
    id INT PRIMARY KEY AUTO_INCREMENT,
    age TINYINT UNSIGNED,              -- 年龄 0-255 足够
    view_count INT UNSIGNED,           -- 浏览次数
    total_orders BIGINT UNSIGNED       -- 总订单数(可能很大)
);

-- UNSIGNED 表示无符号(只有正数)
INSERT INTO user_stats (age, view_count, total_orders) 
VALUES (25, 1000000, 9999999999);
▶ 试一试
💡 提示: 选择够用的最小类型,节省存储空间。年龄用 TINYINT,用户 ID 用 BIGINT。


4. 浮点与定点类型

类型 字节 精度 适用场景
FLOAT 4 6-7 位 科学计算
DOUBLE 8 15-16 位 科学计算
DECIMAL(M,D) 可变 精确 金额、财务

M = 总位数,D = 小数位数。DECIMAL(10,2) 表示最多 10 位整数 + 2 位小数。

▶ 示例:DECIMAL 用法

SQL
CREATE TABLE financials (
    id INT PRIMARY KEY,
    amount DECIMAL(12,2),       -- 金额,最大 9999999999.99
    rate DECIMAL(5,4),          -- 比率,最大 9.9999
    quantity DECIMAL(8,0)       -- 整数数量
);

INSERT INTO financials VALUES (1, 1234567.89, 0.0850, 1000);
SELECT * FROM financials;
▶ 试一试

输出:

TEXT 📖 仅展示
+----+-------------+--------+----------+
| id | amount      | rate   | quantity |
+----+-------------+--------+----------+
|  1 | 1234567.89  | 0.0850 |     1000 |
+----+-------------+--------+----------+

5. 字符串类型

类型 最大长度 特点 适用场景
CHAR(N) 255 字节 固定长度,速度快 手机号、身份证、MD5
VARCHAR(N) 65535 字节 可变长度,节省空间 用户名、邮箱、标题
TINYTEXT 255 字节 文本 短文本
TEXT 65535 字节 文本 文章内容
MEDIUMTEXT 16M 文本 长文章
LONGTEXT 4G 文本 超长文本
ENUM 65535 个值 枚举 状态、类型
SET 64 个值 集合 多选标签

(1) CHAR vs VARCHAR

SQL
-- CHAR(10) 固定长度,存储 'abc' 占 10 字节
-- VARCHAR(10) 可变长度,存储 'abc' 占 4 字节(3+1长度前缀)

CREATE TABLE phones (
    -- 手机号固定 11 位,用 CHAR 更快
    mobile CHAR(11),
    -- 用户名长度不定,用 VARCHAR 更省
    username VARCHAR(50)
);

▶ 示例:ENUM 枚举类型

SQL
CREATE TABLE orders (
    id INT PRIMARY KEY,
    status ENUM('pending', 'paid', 'shipped', 'completed', 'cancelled') DEFAULT 'pending'
);

INSERT INTO orders (id, status) VALUES (1, 'paid');
INSERT INTO orders (id) VALUES (2);  -- 默认 'pending'

-- ENUM 存储的是数字索引(1,2,3...),不是字符串
SELECT status, status + 0 AS index_num FROM orders;
▶ 试一试

输出:

TEXT 📖 仅展示
+---------+-----------+
| status  | index_num |
+---------+-----------+
| paid    |         2 |
| pending |         1 |
+---------+-----------+

6. 日期时间类型

类型 格式 范围 字节
DATE YYYY-MM-DD 1000-01-01 ~ 9999-12-31 3
TIME HH:MM:SS -838:59:59 ~ 838:59:59 3
DATETIME YYYY-MM-DD HH:MM:SS 1000-01-01 ~ 9999-12-31 8
TIMESTAMP YYYY-MM-DD HH:MM:SS 1970-01-01 ~ 2038-01-19 4
YEAR YYYY 1901 ~ 2155 1

(1) DATETIME vs TIMESTAMP

维度 DATETIME TIMESTAMP
范围 1000~9999 年 1970~2038 年
存储 8 字节 4 字节
时区 不转换 自动转 UTC
推荐 历史日期 记录创建/修改时间

▶ 示例:日期时间用法

SQL
CREATE TABLE events (
    id INT PRIMARY KEY AUTO_INCREMENT,
    event_name VARCHAR(100),
    event_date DATE,
    start_time TIME,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

INSERT INTO events (event_name, event_date, start_time) 
VALUES ('Tech Conference', '2026-09-15', '09:00:00');

SELECT * FROM events;
▶ 试一试

输出:

TEXT 📖 仅展示
+----+----------------+------------+------------+---------------------+---------------------+
| id | event_name     | event_date | start_time | created_at          | updated_at          |
+----+----------------+------------+------------+---------------------+---------------------+
|  1 | Tech Conference| 2026-09-15 | 09:00:00   | 2026-07-03 10:00:00 | 2026-07-03 10:00:00 |
+----+----------------+------------+------------+---------------------+---------------------+

7. JSON 类型(MySQL 8.0+)

▶ 示例:JSON 操作

SQL
CREATE TABLE products (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    attributes JSON
);

INSERT INTO products (name, attributes) VALUES 
('iPhone', '{"color": "black", "storage": 128, "tags": ["phone", "apple"]}');

-- 提取 JSON 值
SELECT 
    name,
    attributes->>'$.color' AS color,
    attributes->>'$.storage' AS storage
FROM products;

-- JSON 数组查询
SELECT * FROM products WHERE JSON_CONTAINS(attributes->'$.tags', '"apple"');
▶ 试一试

输出:

TEXT 📖 仅展示
+--------+-------+---------+
| name   | color | storage |
+--------+-------+---------+
| iPhone | black | 128     |
+--------+-------+---------+

8. 数据类型选择最佳实践

场景 推荐类型 原因
主键 ID BIGINT AUTO_INCREMENT 范围大,性能好
用户名 VARCHAR(50) 可变长度,节省空间
邮箱 VARCHAR(100) 可变长度
手机号 CHAR(11) 固定长度,查询快
密码哈希 CHAR(60) bcrypt 固定 60 字符
金额 DECIMAL(10,2) 精确计算
状态 ENUM 或 TINYINT 有限选项
文章内容 TEXT 长文本
创建时间 TIMESTAMP 自动管理,4字节
JSON 数据 JSON 支持索引和函数

❓ 常见问题

Q VARCHAR(255) 和 VARCHAR(256) 有什么区别?
A VARCHAR 长度 ≤255 用 1 字节存长度,>255 用 2 字节。没有性能本质区别,但 255 是常用分界点。
Q TIMESTAMP 2038 年问题怎么办?
A MySQL 8.0 已经在规划修复。如果担心,用 DATETIME 代替。
Q 一个字段可以存多个值吗?
A 可以用 SET 类型或 JSON 数组,但推荐拆成关联表(更规范)。
Q TEXT 字段可以建索引吗?
A 可以,但只能建前缀索引(INDEX(col(100)))。如果需要完整索引,考虑用 VARCHAR。

📖 小节


📝 作业

  1. 基础题(难度⭐):为电商系统设计 products 表,选择合适的数据类型存储名称、价格、库存、状态、描述。

  2. 进阶题(难度⭐⭐):创建一个 user_profiles 表,包含 JSON 类型的 preferences 字段,练习 JSON 值的提取和查询。

  3. 挑战题(难度⭐⭐⭐):对比 DECIMAL(10,2) 和 FLOAT 在存储金额时的精度差异,用实验证明 DECIMAL 的精确性。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏